diff --git a/bbot/core/helpers/interactsh.py b/bbot/core/helpers/interactsh.py index 38066e4d44..5c2eb0e526 100644 --- a/bbot/core/helpers/interactsh.py +++ b/bbot/core/helpers/interactsh.py @@ -234,7 +234,9 @@ async def poll(self): try: r = await self.parent_helper.request( - f"https://{self.server}/poll?id={self.correlation_id}&secret={self.secret}", headers=headers + f"https://{self.server}/poll?id={self.correlation_id}&secret={self.secret}", + headers=headers, + timeout=15, ) if r is None: raise InteractshError("Error polling interact.sh: No response from server") diff --git a/bbot/modules/lightfuzz/lightfuzz.py b/bbot/modules/lightfuzz/lightfuzz.py index 972d1aa9c5..4cbfcd7888 100644 --- a/bbot/modules/lightfuzz/lightfuzz.py +++ b/bbot/modules/lightfuzz/lightfuzz.py @@ -13,11 +13,13 @@ class lightfuzz(BaseModule): "force_common_headers": False, "enabled_submodules": ["sqli", "cmdi", "xss", "path", "ssti", "crypto", "serial", "esi"], "disable_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.", + "avoid_wafs": "Avoid running against confirmed WAFs, which are likely to block lightfuzz requests", } meta = { @@ -38,6 +40,7 @@ async def setup(self): self.disable_post = self.config.get("disable_post", False) self.enabled_submodules = self.config.get("enabled_submodules") self.interactsh_disable = self.scan.config.get("interactsh_disable", False) + self.avoid_wafs = self.scan.config.get("avoid_wafs", True) self.submodules = {} if not self.enabled_submodules: @@ -167,8 +170,16 @@ async def finish(self): except InteractshError as e: self.debug(f"Error in interact.sh: {e}") - # If we've disabled fuzzing POST parameters, back out of POSTPARAM WEB_PARAMETER events as quickly as possible async def filter_event(self, event): + # 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 + parsed_url = getattr(event, "parsed_url", None) + url = parsed_url.geturl() if parsed_url else "unknown" + self.debug(f"Skipping {event.type} because it is likely to be blocked by a WAF. URL: {url}") + return False + + # 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": return False, "POST parameter disabled in lightfuzz module" return True diff --git a/bbot/presets/web/lightfuzz-heavy.yml b/bbot/presets/web/lightfuzz-heavy.yml index 0dd1db4c4b..55cf6e3615 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 modules, and adds paramminer modules for parameter discovery. Avoids running against confirmed WAFs. include: - lightfuzz-medium diff --git a/bbot/presets/web/lightfuzz-light.yml b/bbot/presets/web/lightfuzz-light.yml index a319928f9b..85bd2a81a1 100644 --- a/bbot/presets/web/lightfuzz-light.yml +++ b/bbot/presets/web/lightfuzz-light.yml @@ -12,6 +12,7 @@ config: lightfuzz: enabled_submodules: [path,sqli,xss] # only look for the most common vulnerabilities disable_post: True # don't send POST requests (less aggressive) + avoid_wafs: True conditions: - | diff --git a/bbot/presets/web/lightfuzz-medium.yml b/bbot/presets/web/lightfuzz-medium.yml index ceb15ebbeb..f576eb9832 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 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. include: - lightfuzz-light diff --git a/bbot/presets/web/lightfuzz-superheavy.yml b/bbot/presets/web/lightfuzz-superheavy.yml index f5149c15c1..f05389d2c1 100644 --- a/bbot/presets/web/lightfuzz-superheavy.yml +++ b/bbot/presets/web/lightfuzz-superheavy.yml @@ -9,5 +9,6 @@ config: 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] + avoid_wafs: False excavate: speculate_params: True # speculate potential parameters extracted from JSON/XML web responses diff --git a/bbot/presets/web/lightfuzz-xss.yml b/bbot/presets/web/lightfuzz-xss.yml index ba09348861..83354cd291 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 vulnerabilities. Avoids running against confirmed WAFs. This is an example of a custom lightfuzz preset, selectively enabling a single lightfuzz module. modules: - httpx 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 539fdbae2c..356ee518ee 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 @@ -2060,3 +2060,89 @@ class Test_Lightfuzz_envelope_isolation_paddingoracle_reflecting(Test_Lightfuzz_ } }, } + + +# Test filter_event method with WAF tags +class Test_Lightfuzz_filter_event(ModuleTestBase): + targets = ["http://127.0.0.1:8888"] + modules_overrides = ["httpx", "lightfuzz"] + config_overrides = { + "interactsh_disable": True, + "modules": { + "lightfuzz": { + "enabled_submodules": ["xss"], + "avoid_wafs": True, + } + }, + } + + async def setup_after_prep(self, module_test): + # Create test events with WAF tags + self.url_event_with_waf = module_test.scan.make_event( + "http://127.0.0.1:8888/", + "URL", + module_test.scan.root_event, + module="httpx", + tags=["status-200", "distance-0", "waf"], + ) + + self.web_param_event_with_waf = module_test.scan.make_event( + { + "host": "127.0.0.1", + "type": "GETPARAM", + "name": "test", + "original_value": "value", + "url": "http://127.0.0.1:8888/", + "description": "Test parameter", + }, + "WEB_PARAMETER", + module_test.scan.root_event, + module="excavate", + tags=["distance-0", "waf"], + ) + + self.url_event_without_waf = module_test.scan.make_event( + "http://127.0.0.1:8888/", + "URL", + module_test.scan.root_event, + module="httpx", + tags=["status-200", "distance-0"], + ) + + self.web_param_event_without_waf = module_test.scan.make_event( + { + "host": "127.0.0.1", + "type": "GETPARAM", + "name": "test", + "original_value": "value", + "url": "http://127.0.0.1:8888/", + "description": "Test parameter", + }, + "WEB_PARAMETER", + module_test.scan.root_event, + module="excavate", + tags=["distance-0"], + ) + + async def test_filter_event(self, module_test): + lightfuzz_module = module_test.scan.modules["lightfuzz"] + + # Test URL event with WAF tag - should be filtered out + result = await lightfuzz_module.filter_event(self.url_event_with_waf) + assert result is False, "URL event with waf tag should be filtered out" + + # Test WEB_PARAMETER event with WAF tag - should be filtered out + result = await lightfuzz_module.filter_event(self.web_param_event_with_waf) + assert result is False, "WEB_PARAMETER event with waf tag should be filtered out" + + # Test URL event without WAF tag - should not be filtered + result = await lightfuzz_module.filter_event(self.url_event_without_waf) + assert result is True, "URL event without WAF tag should not be filtered" + + # Test WEB_PARAMETER event without WAF tag - should not be filtered + result = await lightfuzz_module.filter_event(self.web_param_event_without_waf) + assert result is True, "WEB_PARAMETER event without WAF tag should not be filtered" + + def check(self, module_test, events): + # This test doesn't need to check events since it's testing the filter method directly + pass