async def test_xss_with_strong_csp(): persister = AsyncMock() request = Request("http://127.0.0.1:65081/strong_csp.php?content=Hello%20there") request.path_id = 42 crawler = AsyncCrawler("http://127.0.0.1:65081/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_xss(crawler, persister, logger, options, Event()) module.do_post = False await module.attack(request) assert persister.add_payload.call_count assert _("Warning: Content-Security-Policy is present!") in persister.add_payload.call_args_list[0][1]["info"] await crawler.close()
async def test_title_false_positive(): # We should fail at escaping the title tag and we should be aware of it persister = AsyncMock() request = Request("http://127.0.0.1:65081/title_false_positive.php?title=yolo&fixed=yes") request.path_id = 42 crawler = AsyncCrawler("http://127.0.0.1:65081/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_xss(crawler, persister, logger, options, Event()) module.do_post = False await module.attack(request) assert not persister.add_payload.call_count await crawler.close()
def test_title_false_positive(): # We should fail at escaping the title tag and we should be aware of it persister = FakePersister() request = Request( "http://127.0.0.1:65081/title_false_positive.php?title=yolo&fixed=yes") request.path_id = 42 crawler = Crawler("http://127.0.0.1:65081/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_xss(crawler, persister, logger, options) module.do_post = False module.attack(request) assert persister.vulnerabilities == []
def test_bad_separator_used(): persister = FakePersister() request = Request("http://127.0.0.1:65081/confuse_separator.php?number=42") request.path_id = 42 crawler = Crawler("http://127.0.0.1:65081/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_xss(crawler, persister, logger, options) module.do_post = False module.attack(request) assert persister.vulnerabilities used_payload = persister.vulnerabilities[0][1].lower() assert used_payload.startswith("\">")
async def test_rare_tag_and_event(): persister = AsyncMock() request = Request("http://127.0.0.1:65081/filter_common_keywords.php?msg=test") request.path_id = 42 crawler = AsyncCrawler("http://127.0.0.1:65081/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_xss(crawler, persister, logger, options, Event()) module.do_post = False await module.attack(request) assert persister.add_payload.call_count used_payload = persister.add_payload.call_args_list[0][1]["request"].get_params[0][1].lower() assert used_payload.startswith("<custom\nchecked\nonpointerenter=") await crawler.close()
async def test_escape_with_style(): persister = AsyncMock() request = Request("http://127.0.0.1:65081/escape_with_style.php?color=green") request.path_id = 42 crawler = AsyncCrawler("http://127.0.0.1:65081/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_xss(crawler, persister, logger, options, Event()) module.do_post = False await module.attack(request) assert persister.add_payload.call_count used_payload = persister.add_payload.call_args_list[0][1]["request"].get_params[0][1].lower() assert used_payload.startswith("</style>") await crawler.close()
async def test_bad_separator_used(): persister = AsyncMock() request = Request("http://127.0.0.1:65081/confuse_separator.php?number=42") request.path_id = 42 crawler = AsyncCrawler("http://127.0.0.1:65081/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_xss(crawler, persister, logger, options, Event()) module.do_post = False await module.attack(request) assert persister.add_payload.call_count used_payload = persister.add_payload.call_args_list[0][1]["request"].get_params[0][1].lower() assert used_payload.startswith("\">") await crawler.close()
def test_rare_tag_and_event(): persister = FakePersister() request = Request( "http://127.0.0.1:65081/filter_common_keywords.php?msg=test") request.path_id = 42 crawler = Crawler("http://127.0.0.1:65081/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_xss(crawler, persister, logger, options) module.do_post = False module.attack(request) assert persister.vulnerabilities used_payload = persister.vulnerabilities[0][1].lower() assert used_payload.startswith("<custom\nchecked\nonpointerenter=")
def test_attr_escape(): # We should succeed at closing the attribute value and the opening tag persister = FakePersister() request = Request("http://127.0.0.1:65081/attr_escape.php?state=checked") request.path_id = 42 crawler = Crawler("http://127.0.0.1:65081/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_xss(crawler, persister, logger, options) module.do_post = False module.attack(request) assert persister.vulnerabilities assert persister.vulnerabilities[0][0] == "state" assert persister.vulnerabilities[0][1].lower().startswith("><script>")
def test_xss_with_weak_csp(): persister = FakePersister() request = Request( "http://127.0.0.1:65081/weak_csp.php?content=Hello%20there") request.path_id = 42 crawler = Crawler("http://127.0.0.1:65081/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_xss(crawler, persister, logger, options) module.do_post = False module.attack(request) assert persister.vulnerabilities assert _("Warning: Content-Security-Policy is present!" ) not in persister.vulnerabilities[0][2]
def test_escape_with_style(): persister = FakePersister() request = Request( "http://127.0.0.1:65081/escape_with_style.php?color=green") request.path_id = 42 crawler = Crawler("http://127.0.0.1:65081/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_xss(crawler, persister, logger, options) module.do_post = False module.attack(request) assert persister.vulnerabilities used_payload = persister.vulnerabilities[0][1].lower() assert used_payload.startswith("</style>")
def test_xss_inside_tag_input(): persister = FakePersister() request = Request("http://127.0.0.1:65081/input_text_strip_tags.php?uid=5") request.path_id = 42 crawler = Crawler("http://127.0.0.1:65081/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_xss(crawler, persister, logger, options) module.do_post = False module.attack(request) assert persister.vulnerabilities assert persister.vulnerabilities[0][0] == "uid" used_payload = persister.vulnerabilities[0][1].lower() assert "<" not in used_payload and ">" not in used_payload and "autofocus/onfocus" in used_payload
async def test_xss_uppercase_no_script(): persister = AsyncMock() request = Request("http://127.0.0.1:65081/uppercase_no_script.php?name=obiwan") request.path_id = 42 crawler = AsyncCrawler("http://127.0.0.1:65081/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_xss(crawler, persister, logger, options, Event()) module.do_post = False await module.attack(request) assert persister.add_payload.call_count assert persister.add_payload.call_args_list[0][1]["parameter"] == "name" used_payload = persister.add_payload.call_args_list[0][1]["request"].get_params[0][1].lower() assert used_payload.startswith("<svg onload=&") await crawler.close()
async def test_frame_src_no_escape(): persister = AsyncMock() request = Request("http://127.0.0.1:65081/frame_src_no_escape.php?url=https://wapiti.sourceforge.io/") request.path_id = 42 crawler = AsyncCrawler("http://127.0.0.1:65081/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_xss(crawler, persister, logger, options, Event()) module.do_post = False await module.attack(request) assert persister.add_payload.call_count assert persister.add_payload.call_args_list[0][1]["parameter"] == "url" used_payload = persister.add_payload.call_args_list[0][1]["request"].get_params[0][1].lower() assert used_payload.startswith("javascript:alert(/w") await crawler.close()
def test_script_filter_bypass(): # We should succeed at bypass the <script filter persister = FakePersister() request = Request( "http://127.0.0.1:65081/script_tag_filter.php?name=kenobi") request.path_id = 42 crawler = Crawler("http://127.0.0.1:65081/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_xss(crawler, persister, logger, options) module.do_post = False module.attack(request) assert persister.vulnerabilities assert persister.vulnerabilities[0][0] == "name" assert persister.vulnerabilities[0][1].lower().startswith("<svg")
async def test_attr_quote_escape(): # We should succeed at closing the attribute value and the opening tag persister = AsyncMock() request = Request("http://127.0.0.1:65081/attr_quote_escape.php?class=custom") request.path_id = 42 crawler = AsyncCrawler("http://127.0.0.1:65081/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_xss(crawler, persister, logger, options, Event()) module.do_post = False await module.attack(request) assert persister.add_payload.call_count assert persister.add_payload.call_args_list[0][1]["parameter"] == "class" assert persister.add_payload.call_args_list[0][1]["request"].get_params[0][1].lower().startswith("'></pre>") await crawler.close()
async def test_script_filter_bypass(): # We should succeed at bypass the <script filter persister = AsyncMock() request = Request("http://127.0.0.1:65081/script_tag_filter.php?name=kenobi") request.path_id = 42 crawler = AsyncCrawler("http://127.0.0.1:65081/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_xss(crawler, persister, logger, options, Event()) module.do_post = False await module.attack(request) assert persister.add_payload.call_count assert persister.add_payload.call_args_list[0][1]["parameter"] == "name" assert persister.add_payload.call_args_list[0][1]["request"].get_params[0][1].lower().startswith("<svg") await crawler.close()
async def test_xss_inside_tag_link(): persister = AsyncMock() request = Request("http://127.0.0.1:65081/link_href_strip_tags.php?url=http://perdu.com/") request.path_id = 42 crawler = AsyncCrawler("http://127.0.0.1:65081/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_xss(crawler, persister, logger, options, Event()) module.do_post = False await module.attack(request) assert persister.add_payload.call_count assert persister.add_payload.call_args_list[0][1]["parameter"] == "url" used_payload = persister.add_payload.call_args_list[0][1]["request"].get_params[0][1].lower() assert "<" not in used_payload and ">" not in used_payload and "autofocus href onfocus" in used_payload await crawler.close()
def test_xss_uppercase_no_script(): persister = FakePersister() request = Request( "http://127.0.0.1:65081/uppercase_no_script.php?name=obiwan") request.path_id = 42 crawler = Crawler("http://127.0.0.1:65081/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_xss(crawler, persister, logger, options) module.do_post = False module.attack(request) assert persister.vulnerabilities assert persister.vulnerabilities[0][0] == "name" used_payload = persister.vulnerabilities[0][1].lower() assert used_payload.startswith("<svg onload=&")
def test_title_positive(): # We should succeed at escaping the title tag persister = FakePersister() request = Request("http://127.0.0.1:65081/title_false_positive.php?title=yolo") request.path_id = 42 persister.requests.append(request) crawler = Crawler("http://127.0.0.1:65081/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_xss(crawler, persister, logger, options) module.do_post = False for __ in module.attack(): pass assert persister.vulnerabilities assert persister.vulnerabilities[0][0] == "title" assert persister.vulnerabilities[0][1].startswith("</title>")
def test_tag_name_escape(): # We should succeed at closing the attribute value and the opening tag persister = FakePersister() request = Request("http://127.0.0.1:65081/tag_name_escape.php?tag=textarea") request.path_id = 42 persister.requests.append(request) crawler = Crawler("http://127.0.0.1:65081/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_xss(crawler, persister, logger, options) module.do_post = False for __ in module.attack(): pass assert persister.vulnerabilities assert persister.vulnerabilities[0][0] == "tag" assert persister.vulnerabilities[0][1].lower().startswith("script>")
def test_xss_inside_tag_link(): persister = FakePersister() request = Request("http://127.0.0.1:65081/link_href_strip_tags.php?url=http://perdu.com/") request.path_id = 42 persister.requests.append(request) crawler = Crawler("http://127.0.0.1:65081/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_xss(crawler, persister, logger, options) module.do_post = False for __ in module.attack(): pass assert persister.vulnerabilities assert persister.vulnerabilities[0][0] == "url" used_payload = persister.vulnerabilities[0][1].lower() assert "<" not in used_payload and ">" not in used_payload and "autofocus href onfocus" in used_payload
def test_frame_src_no_escape(): persister = FakePersister() request = Request( "http://127.0.0.1:65081/frame_src_no_escape.php?url=https://wapiti.sourceforge.io/" ) request.path_id = 42 crawler = Crawler("http://127.0.0.1:65081/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_xss(crawler, persister, logger, options) module.do_post = False module.attack(request) assert persister.vulnerabilities assert persister.vulnerabilities[0][0] == "url" used_payload = persister.vulnerabilities[0][1].lower() assert used_payload.startswith("javascript:alert(/w")
async def test_attr_double_quote_escape(): # We should succeed at closing the attribute value and the opening tag persister = FakePersister() request = Request( "http://127.0.0.1:65081/attr_double_quote_escape.php?class=custom") request.path_id = 42 crawler = AsyncCrawler("http://127.0.0.1:65081/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_xss(crawler, persister, logger, options, Event()) module.do_post = False await module.attack(request) assert persister.vulnerabilities assert persister.vulnerabilities[0][0] == "class" assert persister.vulnerabilities[0][1].lower().startswith("\"></pre>") await crawler.close()
async def test_partial_tag_name_escape(): # We should succeed at closing the attribute value and the opening tag persister = FakePersister() request = Request( "http://127.0.0.1:65081/partial_tag_name_escape.php?importance=2") request.path_id = 42 crawler = AsyncCrawler("http://127.0.0.1:65081/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_xss(crawler, persister, logger, options, Event()) module.do_post = False await module.attack(request) assert persister.vulnerabilities assert persister.vulnerabilities[0][0] == "importance" assert persister.vulnerabilities[0][1].lower().startswith("/><script>") await crawler.close()
def test_title_positive(): # We should succeed at escaping the title tag persister = FakePersister() request = Request( "http://127.0.0.1:65081/title_false_positive.php?title=yolo") request.path_id = 42 crawler = Crawler("http://127.0.0.1:65081/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_xss(crawler, persister, logger, options) module.do_post = False module.attack(request) assert persister.vulnerabilities assert persister.vulnerabilities[0][0] == "title" assert persister.vulnerabilities[0][1].startswith("</title>") assert _("Warning: Content-Security-Policy is present!" ) not in persister.vulnerabilities[0][2]
async def test_whole_stuff(): # Test attacking all kind of parameter without crashing respx.get(url__regex=r"http://perdu\.com/.*").mock( return_value=httpx.Response(200, text="Hello there")) respx.post(url__regex=r"http://perdu\.com/.*").mock( return_value=httpx.Response(200, text="Hello there")) persister = AsyncMock() all_requests = [] request = Request("http://perdu.com/") request.path_id = 1 all_requests.append(request) request = Request("http://perdu.com/?foo=bar") request.path_id = 2 all_requests.append(request) request = Request("http://perdu.com/?foo=bar", post_params=[["a", "b"]], file_params=[[ "file", ("calendar.xml", "<xml>Hello there</xml", "application/xml") ]]) request.path_id = 3 all_requests.append(request) crawler = AsyncCrawler("http://perdu.com/", timeout=1) options = {"timeout": 10, "level": 2} logger = Mock() module = mod_xss(crawler, persister, logger, options, Event()) module.verbose = 2 module.do_post = True for request in all_requests: await module.attack(request) assert True await crawler.close()
async def test_title_positive(): # We should succeed at escaping the title tag persister = AsyncMock() request = Request("http://127.0.0.1:65081/title_false_positive.php?title=yolo") request.path_id = 42 crawler = AsyncCrawler("http://127.0.0.1:65081/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_xss(crawler, persister, logger, options, Event()) module.do_post = False await module.attack(request) assert persister.add_payload.call_count assert persister.add_payload.call_args_list[0][1]["module"] == "xss" assert persister.add_payload.call_args_list[0][1]["category"] == _("Cross Site Scripting") assert persister.add_payload.call_args_list[0][1]["parameter"] == "title" assert persister.add_payload.call_args_list[0][1]["request"].get_params[0][1].startswith("</title>") assert _( "Warning: Content-Security-Policy is present!" ) not in persister.add_payload.call_args_list[0][1]["info"] await crawler.close()
def test_whole_stuff(): # Test attacking all kind of parameter without crashing responses.add(responses.GET, re.compile(r"http://perdu.com/"), body="Hello there") responses.add(responses.POST, re.compile(r"http://perdu.com/"), body="Hello there") persister = FakePersister() request = Request("http://perdu.com/") request.path_id = 1 persister.requests.append(request) request = Request("http://perdu.com/?foo=bar") request.path_id = 2 persister.requests.append(request) request = Request( "http://perdu.com/?foo=bar", post_params=[["a", "b"]], file_params=[["file", ["calendar.xml", "<xml>Hello there</xml"]]]) request.path_id = 3 persister.requests.append(request) crawler = Crawler("http://perdu.com/", timeout=1) options = {"timeout": 10, "level": 2} logger = Mock() module = mod_xss(crawler, persister, logger, options) module.verbose = 2 module.do_post = True for __ in module.attack(): pass assert True