def test_meta_detection(): # Test if application is detected using its meta regex responses.add(responses.GET, url="http://perdu.com/", body="<html><head><title>Vous Etes Perdu ?</title> \ <meta name=\"generator\" content=\"Planet/1.6.2\"> \ </head><body><h1>Perdu sur l'Internet ?</h1> \ <h2>Pas de panique, on va vous aider</h2> \ <strong><pre> * <----- vous êtes ici</pre></strong> \ </body></html>") persister = FakePersister() request = Request("http://perdu.com/") request.path_id = 1 persister.requests.append(request) crawler = Crawler("http://perdu.com/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_wapp(crawler, persister, logger, options) module.verbose = 2 for __ in module.attack(): pass assert persister.additionals assert persister.additionals[0] == "Planet 1.6.2"
def test_script_detection(): # Test if application is detected using its script regex responses.add( responses.GET, url="http://perdu.com/", body= "<html><head><title>Vous Etes Perdu ?</title></head><body><h1>Perdu sur l'Internet ?</h1> \ <h2>Pas de panique, on va vous aider</h2> \ <strong><pre> * <----- vous êtes ici</pre></strong> \ <script src=\"http://chartjs.org/dist/1.4.2/Chart.js\"></script>\ </body></html>") persister = FakePersister() request = Request("http://perdu.com/") request.path_id = 1 persister.requests.append(request) crawler = Crawler("http://perdu.com/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_wapp(crawler, persister, logger, options) module.verbose = 2 for __ in module.attack(): pass assert persister.additionals assert persister.additionals[0] == "Chart.js 1.4.2"
def test_cookies_detection(): # Test if application is detected using its cookies regex responses.add( responses.GET, url="http://perdu.com/", body= "<html><head><title>Vous Etes Perdu ?</title></head><body><h1>Perdu sur l'Internet ?</h1> \ <h2>Pas de panique, on va vous aider</h2> \ <strong><pre> * <----- vous êtes ici</pre></strong> \ </body></html>", headers={"Set-Cookie": "ci_csrf_token=4.1"}) persister = FakePersister() request = Request("http://perdu.com/") request.path_id = 1 persister.requests.append(request) crawler = Crawler("http://perdu.com/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_wapp(crawler, persister, logger, options) module.verbose = 2 for __ in module.attack(): pass assert persister.additionals assert persister.additionals[0] == "CodeIgniter 2+"
def test_multi_detection(): # Test if application is detected using several ways responses.add( responses.GET, url="http://perdu.com/", body="<html><head><title>Vous Etes Perdu ?</title> \ <meta name=\"generator\" content=\"WordPress 5.6.1\"> \ </head><body><h1>Perdu sur l'Internet ?</h1> \ <h2>Pas de panique, on va vous aider</h2> \ <strong><pre> * <----- vous êtes ici</pre></strong> \ <script type=\"text/javascript\" src=\"https://perdu.com/wp-includes/js/wp-embed.min.js\" ></script> \ </body></html>", headers={"link": "<http://perdu.com/wp-json/>; rel=\"https://api.w.org/\""} ) persister = FakePersister() request = Request("http://perdu.com/") request.path_id = 1 persister.requests.append(request) crawler = Crawler("http://perdu.com/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_wapp(crawler, persister, logger, options) module.verbose = 2 for __ in module.attack(): pass assert persister.additionals assert persister.additionals[-1] == '{"versions": ["5.6.1"], "name": "WordPress", "categories": ["CMS", "Blogs"]}'
def test_html_detection(): # Test if application is detected using its html regex responses.add( responses.GET, url="http://perdu.com/", body= "<html><head><title>Vous Etes Perdu ?</title></head><body><h1>Perdu sur l'Internet ?</h1> \ <h2>Pas de panique, on va vous aider</h2> \ <strong><pre> * <----- vous êtes ici</pre></strong> \ <title>Powered by <a href=\"http://atlassian.com/software/confluence\">Atlassian Confluence</a> 2.8.4</p> \ </body></html>") persister = FakePersister() request = Request("http://perdu.com/") request.path_id = 1 persister.requests.append(request) crawler = Crawler("http://perdu.com/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_wapp(crawler, persister, logger, options) module.verbose = 2 for __ in module.attack(): pass assert persister.additionals assert persister.additionals[0] == "Atlassian Confluence 2.8.4"
def test_headers_detection(): # Test if application is detected using its headers regex responses.add( responses.GET, url="http://perdu.com/", body="<html><head><title>Vous Etes Perdu ?</title></head><body><h1>Perdu sur l'Internet ?</h1> \ <h2>Pas de panique, on va vous aider</h2> \ <strong><pre> * <----- vous êtes ici</pre></strong> \ </body></html>", headers={"Server": "Cherokee/1.3.4"} ) persister = FakePersister() request = Request("http://perdu.com/") request.path_id = 1 persister.requests.append(request) crawler = Crawler("http://perdu.com/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_wapp(crawler, persister, logger, options) module.verbose = 2 for __ in module.attack(): pass assert persister.additionals assert persister.additionals[0] == '{"versions": ["1.3.4"], "name": "Cherokee", "categories": ["Web servers"]}'
def test_html_detection(): # Test if application is detected using its html regex responses.add( responses.GET, url="http://perdu.com/", body="<html><head><title>FishEye 2.8.4</title> \ </head><body><h1>Perdu sur l'Internet ?</h1> \ <h2>Pas de panique, on va vous aider</h2> \ </body></html>" ) persister = FakePersister() request = Request("http://perdu.com/") request.path_id = 1 persister.requests.append(request) crawler = Crawler("http://perdu.com/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_wapp(crawler, persister, logger, options) module.verbose = 2 for __ in module.attack(): pass assert persister.additionals assert persister.additionals[0] == '{"versions": ["2.8.4"], "name": "Atlassian FishEye", "categories": ["Development"]}'
def test_false_positive_request_count(): responses.add( responses.GET, # Beware! Responses seems to do a match on regex and not a search, give it full URL re.compile(r"http://perdu.com/blind_sql.php\?vuln1=sleep"), body=ReadTimeout("Read timed out")) responses.add(responses.GET, re.compile(r"http://perdu.com/blind_sql.php\?vuln1=hello"), body=ReadTimeout("Read timed out")) persister = FakePersister() request = Request("http://perdu.com/blind_sql.php?vuln1=hello%20there") request.path_id = 42 persister.requests.append(request) crawler = Crawler("http://perdu.com/", timeout=1) options = {"timeout": 1, "level": 1} logger = Mock() module = mod_blindsql(crawler, persister, logger, options) module.verbose = 2 module.do_post = False for __ in module.attack(): pass # Due to the retry decorator we should have 6 requests here # First three to make sure the payload generate timeouts each time # then three more requests with timeouts to make sure the original request is a false positive assert len(responses.calls) == 6
def test_implies_detection(): # Test for implied applications responses.add( responses.GET, url="http://perdu.com/", body= "<html><head><title>Vous Etes Perdu ?</title></head><body><h1>Perdu sur l'Internet ?</h1> \ <h2>Pas de panique, on va vous aider</h2> \ <strong><pre> * <----- vous êtes ici</pre></strong> \ </body></html>", headers={"X-Generator": "Backdrop CMS 4.5"}) persister = FakePersister() request = Request("http://perdu.com") request.path_id = 1 persister.requests.append(request) crawler = Crawler("http://perdu.com") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_wapp(crawler, persister, logger, options) module.verbose = 2 for __ in module.attack(): pass assert persister.additionals assert "Backdrop 4.5" in persister.additionals assert "PHP" in persister.additionals
def test_false_positive(): # Test for false positive responses.add_passthru( "https://raw.githubusercontent.com/AliasIO/wappalyzer/master/src/technologies.json" ) responses.add( responses.GET, url="http://perdu.com/", body= "<html><head><title>Vous Etes Perdu ?</title></head><body><h1>Perdu sur l'Internet ?</h1> \ <h2>Pas de panique, on va vous aider</h2> \ <strong><pre> * <----- vous êtes ici</pre></strong></body></html>" ) persister = FakePersister() request = Request("http://perdu.com/") request.path_id = 1 persister.requests.append(request) crawler = Crawler("http://perdu.com/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_wapp(crawler, persister, logger, options) module.verbose = 2 for __ in module.attack(): pass assert not persister.additionals
def test_true_positive(): responses.add(responses.GET, url="http://perdu.com/?foo=bar", body="Hi there") responses.add( responses.GET, url=re.compile(r"http://perdu.com/\?foo=.*"), body= ("You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version " "for the right syntax to use near '\\\"\\'' at line 1")) persister = FakePersister() request = Request("http://perdu.com/?foo=bar") request.path_id = 1 persister.requests.append(request) crawler = Crawler("http://perdu.com/", timeout=1) options = {"timeout": 10, "level": 1} logger = Mock() module = mod_sql(crawler, persister, logger, options) module.verbose = 2 module.do_post = True for __ in module.attack(): pass assert persister.vulnerabilities
def test_implies_detection(): # Test for implied applications responses.add( responses.GET, url="http://perdu.com/", body= "<html><head><title>Vous Etes Perdu ?</title></head><body><h1>Perdu sur l'Internet ?</h1> \ <h2>Pas de panique, on va vous aider</h2> \ <strong><pre> * <----- vous êtes ici</pre></strong> \ </body></html>", headers={"X-Generator": "Backdrop CMS 4.5"}) persister = FakePersister() request = Request("http://perdu.com") request.path_id = 1 crawler = Crawler("http://perdu.com") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_wapp(crawler, persister, logger, options) module.verbose = 2 module.attack(request) assert persister.additionals assert persister.additionals[ 0] == '{"versions": ["4.5"], "name": "Backdrop", "categories": ["CMS"]}' assert persister.additionals[ 1] == '{"versions": [], "name": "PHP", "categories": ["Programming languages"]}'
def test_qs_limit(): crawler = Crawler("http://127.0.0.1:65080/") explorer = Explorer(crawler) start_urls = deque(["http://127.0.0.1:65080/"]) excluded_urls = [] # We should have root url, huge form page, target and target with POST method assert len(list(explorer.explore(start_urls, excluded_urls))) == 4 crawler = Crawler("http://127.0.0.1:65080/") explorer = Explorer(crawler) # Exclude huge POST form with limit of parameters explorer.qs_limit = 500 start_urls = deque(["http://127.0.0.1:65080/"]) excluded_urls = [] # We should have root url, huge form page, target and target with POST method assert len(list(explorer.explore(start_urls, excluded_urls))) == 3
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") 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_redirect(crawler, persister, logger, options) module.verbose = 2 module.do_post = True for __ in module.attack(): pass assert True
def test_whole_stuff(): responses.add(responses.GET, url="http://perdu.com/", status=200) responses.add_callback(responses.GET, re.compile(r"http://perdu.com/.*"), callback=shellshock_callback) persister = FakePersister() request = Request("http://perdu.com/") request.path_id = 1 request.status = 200 request.set_headers({"content-type": "text/html"}) persister.requests.append(request) request = Request("http://perdu.com/vuln/") request.path_id = 2 request.status = 200 request.set_headers({"content-type": "text/html"}) persister.requests.append(request) crawler = Crawler("http://perdu.com/", timeout=1) options = {"timeout": 10, "level": 2} logger = Mock() module = mod_shellshock(crawler, persister, logger, options) module.verbose = 2 module.do_get = True for __ in module.attack(): pass assert len(persister.vulnerabilities) == 1 assert persister.vulnerabilities[0][0].url == ("http://perdu.com/vuln/")
def test_true_positive(): responses.add(responses.GET, url="http://perdu.com/?foo=bar", body="Hi there") responses.add(responses.GET, url=re.compile(r"http://perdu.com/\?foo=.*"), body="You have an error in your SQL syntax") persister = FakePersister() request = Request("http://perdu.com/?foo=bar") request.path_id = 1 persister.requests.append(request) crawler = Crawler("http://perdu.com/", timeout=1) options = {"timeout": 10, "level": 1} logger = Mock() module = mod_sql(crawler, persister, logger, options) module.verbose = 2 module.do_post = True for __ in module.attack(): pass assert persister.vulnerabilities
def test_true_positive_request_count(): responses.add(responses.GET, re.compile(r"http://perdu.com/blind_sql.php\?vuln1=sleep"), body=ReadTimeout("Read timed out")) responses.add(responses.GET, re.compile(r"http://perdu.com/blind_sql.php\?vuln1=hello"), body="Hello there!") persister = FakePersister() request = Request("http://perdu.com/blind_sql.php?vuln1=hello%20there") request.path_id = 42 persister.requests.append(request) crawler = Crawler("http://perdu.com/", timeout=1) options = {"timeout": 1, "level": 1} logger = Mock() module = mod_blindsql(crawler, persister, logger, options) module.verbose = 2 module.do_post = False for __ in module.attack(): pass # Four requests should be made there: # Three ones due to time-based SQL injection (one for injection, two to be sure) # Then one request to verify that the original request doesn't raise a timeout assert len(responses.calls) == 4
def test_whole_stuff(): # Test attacking all kind of parameter without crashing responses.add( responses.GET, re.compile(r"http://perdu.com/\?a=.*&foo=bar"), body="Hello there" ) responses.add( responses.GET, re.compile(r"http://perdu.com/\?a=b*&foo=.*wapiti.*"), body="Hello there", headers={"wapiti": "3.0.3 version"} ) persister = FakePersister() request = Request("http://perdu.com/?a=b&foo=bar") request.path_id = 1 persister.requests.append(request) crawler = Crawler("http://perdu.com/", timeout=1) options = {"timeout": 10, "level": 2} logger = Mock() module = mod_crlf(crawler, persister, logger, options) module.verbose = 2 module.do_get = True for __ in module.attack(): pass assert persister.vulnerabilities assert persister.vulnerabilities[0][0] == "foo"
def test_detection(): responses.add(responses.GET, re.compile(r"http://perdu.com/\?vuln=.*env.*"), body="PATH=/bin:/usr/bin;PWD=/") responses.add(responses.GET, re.compile(r"http://perdu.com/\?vuln=.*"), body="Hello there") persister = FakePersister() request = Request("http://perdu.com/?vuln=hello") request.path_id = 1 persister.requests.append(request) crawler = Crawler("http://perdu.com/", timeout=1) options = {"timeout": 10, "level": 1} logger = Mock() module = mod_exec(crawler, persister, logger, options) module.verbose = 2 module.attack(request) assert persister.vulnerabilities assert persister.vulnerabilities[0][0] == "vuln" assert "env" in persister.vulnerabilities[0][1]
def test_url_detection(): # Test if application is detected using its url regex responses.add( responses.GET, url="http://perdu.com/owa/auth/logon.aspx", body= "<html><head><title>Vous Etes Perdu ?</title></head><body><h1>Perdu sur l'Internet ?</h1> \ <h2>Pas de panique, on va vous aider</h2> \ <strong><pre> * <----- vous êtes ici</pre></strong></body></html>" ) persister = FakePersister() request = Request("http://perdu.com/owa/auth/logon.aspx") request.path_id = 1 persister.requests.append(request) crawler = Crawler("http://perdu.com/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_wapp(crawler, persister, logger, options) module.verbose = 2 for __ in module.attack(): pass assert persister.additionals assert persister.additionals[2] == "Outlook Web App"
def test_cookies(): responses.add(responses.GET, "http://perdu.com/", body="Hello there!", headers={"Set-Cookie": "foo=bar; Path=/"}) def print_headers_callback(request): return 200, {}, json.dumps(dict(request.headers), indent=2) responses.add_callback(responses.GET, "http://perdu.com/cookies", callback=print_headers_callback) crawler = Crawler("http://perdu.com/") response = crawler.get(Request("http://perdu.com/")) assert "foo=bar" in response.headers["set-cookie"] response = crawler.get(Request("http://perdu.com/cookies")) assert "foo=bar" in response.content
def test_whole_stuff(): # Test attacking all kind of parameter without crashing responses.add(responses.GET, url="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_ssrf(crawler, persister, logger, options) module.verbose = 2 module.do_post = True responses.add( responses.GET, url="https://wapiti3.ovh/get_ssrf.php?id=" + module._session_id, json={ "3": { "66696c65": [{ "date": "2019-08-17T16:52:41+00:00", "url": "https://wapiti3.ovh/ssrf_data/yolo/3/66696c65/31337-0-192.168.2.1.txt", "ip": "192.168.2.1", "method": "GET" }] } }) for __ in module.attack(): pass assert not persister.vulnerabilities # We must trigger finish(à normally called by wapiti.py module.finish() assert persister.vulnerabilities assert persister.vulnerabilities[0][0] == "file" file_params = persister.vulnerabilities[0][1].file_params assert file_params[0][1][0] == "http://external.url/page"
def test_csrf_cases(): persister = FakePersister() request = Request("http://127.0.0.1:65086/") request.path_id = 1 persister.requests.append(request) request = Request( "http://127.0.0.1:65086/", method="POST", post_params=[["email", "*****@*****.**"], ["xsrf_token", "weak"]], ) request.path_id = 2 persister.requests.append(request) request = Request( "http://127.0.0.1:65086/?check=true", method="POST", post_params=[["email", "*****@*****.**"], ["xsrf_token", "weak"]], ) request.path_id = 3 persister.requests.append(request) request = Request( "http://127.0.0.1:65086/?check=true", method="POST", post_params=[["name", "Obiwan"]], ) request.path_id = 4 persister.requests.append(request) crawler = Crawler("http://127.0.0.1:65086/", timeout=1) options = {"timeout": 10, "level": 1} logger = Mock() module = mod_csrf(crawler, persister, logger, options) module.do_post = True module.verbose = 2 for request in persister.requests: if module.must_attack(request): module.attack(request) else: # Not attacked because of GET verb assert request.path_id == 1 assert set(persister.vulnerabilities) == { (2, _("CSRF token '{}' is not properly checked in backend").format( "xsrf_token")), (3, _("CSRF token '{}' might be easy to predict").format("xsrf_token")), (4, _("Lack of anti CSRF token")) }
def test_redirect(): slyfx = "http://www.slyfx.com/" disney = "http://www.disney.com/" responses.add(responses.GET, slyfx, body="Back to disneyland", status=301, headers={"Location": disney}) responses.add(responses.GET, disney, body="Hello there") crawler = Crawler(slyfx) page = crawler.send(Request(slyfx)) assert page.url == slyfx assert not page.history page = crawler.send(Request(slyfx), follow_redirects=True) assert page.url == disney assert page.history[0].url == slyfx
def test_whole_stuff(): # Test attacking all kind of parameter without crashing responses.add(responses.GET, url="http://perdu.com/", body="Default page") responses.add(responses.GET, url="http://perdu.com/admin", body="Hello there", headers={"Location": "/admin/"}, status=301) responses.add(responses.GET, url="http://perdu.com/admin/", body="Hello there") responses.add(responses.GET, url="http://perdu.com/config.inc", body="pass = 123456") responses.add(responses.GET, url="http://perdu.com/admin/authconfig.php", body="Hello there") responses.add(responses.GET, url=re.compile(r"http://perdu.com/.*"), status=404) persister = FakePersister() request = Request("http://perdu.com/") request.path_id = 1 request.set_headers({"content-type": "text/html"}) persister.requests.append(request) crawler = Crawler("http://perdu.com/", timeout=1) options = {"timeout": 10, "level": 2} logger = Mock() with patch("wapitiCore.attack.mod_buster.mod_buster.payloads", [("nawak", set()), ("admin", set()), ("config.inc", set()), ("authconfig.php", set())]): module = mod_buster(crawler, persister, logger, options) module.verbose = 2 module.do_get = True for __ in module.attack(): pass assert module.known_dirs == [ "http://perdu.com/", "http://perdu.com/admin/" ] assert module.known_pages == [ "http://perdu.com/config.inc", "http://perdu.com/admin/authconfig.php" ]
def test_redirect_detection(): persister = FakePersister() request = Request( "http://127.0.0.1:65080/open_redirect.php?yolo=nawak&url=toto") crawler = Crawler("http://127.0.0.1:65080/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_redirect(crawler, persister, logger, options) module.attack(request) assert persister.vulnerabilities == {"url"}
def test_explorer_filtering(): crawler = Crawler("http://127.0.0.1:65080/") explorer = Explorer(crawler) start_urls = deque(["http://127.0.0.1:65080/filters.html"]) excluded_urls = [] results = set([ resource.url for resource in explorer.explore(start_urls, excluded_urls) ]) # We should have current URL and JS URL but without query string. # CSS URL should be excluded assert results == { "http://127.0.0.1:65080/filters.html", "http://127.0.0.1:65080/yolo.js" }
def test_direct_query_string(): persister = FakePersister() request = Request("http://127.0.0.1:65084/xxe/direct/qs.php") request.path_id = 42 crawler = Crawler("http://127.0.0.1:65084/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_xxe(crawler, persister, logger, options) module.do_post = False module.attack(request) assert len(persister.vulnerabilities) assert persister.vulnerabilities[0][0] == "QUERY_STRING"
def test_timesql_false_positive(): persister = FakePersister() request = Request( "http://127.0.0.1:65082/blind_sql.php?vuln2=hello%20there") request.path_id = 42 crawler = Crawler("http://127.0.0.1:65082/", timeout=1) options = {"timeout": 1, "level": 1} logger = Mock() module = mod_timesql(crawler, persister, logger, options) module.do_post = False module.attack(request) assert not persister.vulnerabilities
def test_warning_false_positive(): persister = FakePersister() request = Request("http://127.0.0.1:65080/inclusion.php?yolo=warn&f=toto") request.path_id = 42 persister.requests.append(request) crawler = Crawler("http://127.0.0.1:65080/") options = {"timeout": 10, "level": 2} logger = Mock() module = mod_file(crawler, persister, logger, options) module.do_post = False for __ in module.attack(): pass assert persister.vulnerabilities == [("f", "/etc/services")]