From ade2d5f82c1b77fb9daa80a2a8500078a4539178 Mon Sep 17 00:00:00 2001 From: ekultek Date: Fri, 1 Dec 2017 16:19:26 -0600 Subject: [PATCH] added new headers to search for, patches issue #207, patches issue #211, also patches issue #212 --- etc/checksum/md5sum.md5 | 14 +++++------ etc/xml/headers.xml | 2 ++ lib/attacks/admin_panel_finder/__init__.py | 12 +++++---- lib/attacks/gist_lookup/__init__.py | 22 ++++++++++------ lib/attacks/nmap_scan/__init__.py | 13 +++++----- lib/attacks/xss_scan/__init__.py | 21 ++++++++++++++-- lib/core/common.py | 29 ++++++++++++++++------ lib/core/settings.py | 7 ++++-- 8 files changed, 84 insertions(+), 36 deletions(-) diff --git a/etc/checksum/md5sum.md5 b/etc/checksum/md5sum.md5 index d0ddafc..6c8242b 100644 --- a/etc/checksum/md5sum.md5 +++ b/etc/checksum/md5sum.md5 @@ -11,7 +11,7 @@ d3ad89703575a712a0aeead2b176d8c5 ./etc/html/clickjacking_test_page.html 82cc68f46539d0255f7ce14cd86cd49b ./etc/text_files/link_ext.txt 9659c647c725773e82d130e0f5c73c57 ./etc/text_files/dorks.txt dc7bfc3d7b9b23340ee37806316bd770 ./etc/text_files/xss_payloads.txt -b795ccb193f307a8e9a4a888c018241a ./etc/xml/headers.xml +5250f0aa13b8af4775efa506e77de1ce ./etc/xml/headers.xml d41d8cd98f00b204e9800998ecf8427e ./bin/__init__.py ebd255c3ab49efde3155338e5d596b63 ./bin/unzip_gecko.py dc1eb4ebe0f372af48b5a9c107ebc68d ./bin/drivers/geckodriver-v0.18.0-linux32.tar.gz @@ -62,22 +62,22 @@ bbd8b4c6100070d420d48dc7dfc297eb ./lib/firewall/webknight.py 81a29a14d72980a306fbaec0dc772048 ./lib/firewall/fortigate.py 6ea65a0160c21e144e92334acc2e3667 ./lib/firewall/anquanbao.py 22a0ad8f2fa1a16b651cb5ae37ca9b0d ./lib/firewall/generic.py -67ae989c771f1069095aaae7ec3a96d7 ./lib/attacks/gist_lookup/__init__.py +ddf45537bdcea15d3b428495985bad09 ./lib/attacks/gist_lookup/__init__.py 7183dbd7106ecb436176cebcca4e499f ./lib/attacks/clickjacking_scan/__init__.py d41d8cd98f00b204e9800998ecf8427e ./lib/attacks/__init__.py 4c644b0e3a62b6c1528d34a04837aa35 ./lib/attacks/sqlmap_scan/__init__.py 5e5bb575014ebe613db6bf671d008cf8 ./lib/attacks/sqlmap_scan/sqlmap_opts.py 7bc7a6f3e85651aab3588f087563eded ./lib/attacks/whois_lookup/__init__.py 8ec72bb33df998e32b925e3060d9d17a ./lib/attacks/whois_lookup/whois.py -2d7686f1b9b93c3989bc5f279a1a064a ./lib/attacks/admin_panel_finder/__init__.py -cc5e5838893eba60cf4bd33d38007e32 ./lib/attacks/xss_scan/__init__.py -lib/attacks/nmap_scan/__init__.py ./lib/attacks/nmap_scan/__init__.py +67ac65be1b4394ad80ec0fd3472c5309 ./lib/attacks/admin_panel_finder/__init__.py +75652b6197e9775e58e177f5e2fc680c ./lib/attacks/xss_scan/__init__.py +75652b6197e9775e58e177f5e2fc680c ./lib/attacks/nmap_scan/__init__.py 216999fa0e84866d5c1d96d5676034e4 ./lib/attacks/nmap_scan/nmap_opts.py 888686098a0850750f2435d0e1645944 ./lib/header_check/__init__.py -39221756c132732dbdc2b14772dcab11 ./lib/core/common.py +0721c655d433dbc170756f3e40a786cf ./lib/core/common.py 4433353fb5c55578391d8b4006191ee8 ./lib/core/errors.py d41d8cd98f00b204e9800998ecf8427e ./lib/core/__init__.py -ebcd664dbeda6cb93c9e66c71aa45a33 ./lib/core/settings.py +5f7fd52c614f1a0f280191592d4b08b3 ./lib/core/settings.py 801a4f7ac892b74676c649bd4844ccdb ./lib/core/decorators.py 9a02e5b913d210350545ac26510a63c9 ./var/search/__init__.py 0545ee54ade186681b25d157fb32f350 ./var/search/selenium_search.py diff --git a/etc/xml/headers.xml b/etc/xml/headers.xml index ab2aaf3..038552b 100644 --- a/etc/xml/headers.xml +++ b/etc/xml/headers.xml @@ -5,4 +5,6 @@
+
+
\ No newline at end of file diff --git a/lib/attacks/admin_panel_finder/__init__.py b/lib/attacks/admin_panel_finder/__init__.py index b54770f..63a92d5 100644 --- a/lib/attacks/admin_panel_finder/__init__.py +++ b/lib/attacks/admin_panel_finder/__init__.py @@ -136,11 +136,13 @@ def check_for_admin_page(url, exts, protocol="http://", **kwargs): )) possible_connections.add(true_url) else: - lib.core.settings.logger.error(lib.core.settings.set_color( - "failed to connect got error code {}...".format( - data[2] - ), level=40 - )) + for error_code in lib.core.common.STATUS_CODES.iterkeys(): + if int(data[2].split(":")[0]) == error_code: + lib.core.settings.logger.error(lib.core.settings.set_color( + "failed to connect got error code {} (reason: {})...".format( + data[2], lib.core.common.STATUS_CODES[error_code] + ), level=40 + )) except Exception as e: if verbose: if "" or "timeout: timed out" in str(e): diff --git a/lib/attacks/gist_lookup/__init__.py b/lib/attacks/gist_lookup/__init__.py index 59b2c13..531ad0a 100644 --- a/lib/attacks/gist_lookup/__init__.py +++ b/lib/attacks/gist_lookup/__init__.py @@ -79,12 +79,18 @@ def check_files_for_information(found_url, data_to_search): # we need to create the query to be just the domain name data_to_search = data_to_search.split(".")[1] data_regex_schema = ( - re.compile(r"{}".format(data_to_search), re.I), # a regular match - re.compile(r"(http(s)?)(.//)?{}".format(data_to_search), re.I), # match a URL containing our string - re.compile(r"(.)?{}(.)?".format(data_to_search), re.I), # if it has anything around it - re.compile(r"\b{}".format(data_to_search), re.I), # single boundary match - re.compile(r"\b{}\b".format(data_to_search), re.I), # double boundary match - re.compile(r"{}*".format(data_to_search), re.I) # wildcard match + # a normal regex with our string + re.compile(r"{}".format(data_to_search), re.I), + # match a URL with or without www + re.compile(r"(http(s)?)?(.//)?(www.)?{}".format(data_to_search), re.I), + # match our string and any random character around it (I like to call it the tittyex) + re.compile(r"(.)?{}(.)?".format(data_to_search), re.I), + # single boundary match, checks if it's inside of something else + re.compile(r"\b{}".format(data_to_search), re.I), + # double boundary, same as above but with another boundary + re.compile(r"\b{}\b".format(data_to_search), re.I), + # wildcard match + re.compile(r"{}*".format(data_to_search), re.I) ) total_found = set() try: @@ -98,7 +104,9 @@ def check_files_for_information(found_url, data_to_search): for data_regex in data_regex_schema: if data_regex.search(data.content) is not None: lib.core.settings.logger.info(lib.core.settings.set_color( - "found a match with given specifics, saving full Gist to log file...", level=25 + "found a match with given specifics ('{}'), saving full Gist to log file...".format( + data_regex.pattern + ), level=25 )) total_found.add(found_url) lib.core.common.write_to_log_file( diff --git a/lib/attacks/nmap_scan/__init__.py b/lib/attacks/nmap_scan/__init__.py index 4e4a82c..b1036f3 100644 --- a/lib/attacks/nmap_scan/__init__.py +++ b/lib/attacks/nmap_scan/__init__.py @@ -41,11 +41,10 @@ class NmapHook(object): """ send all the information to a JSON file for further use """ - lib.core.settings.create_dir(self.dir) - full_nmap_path = "{}/{}".format(self.dir, self.file.format(self.ip)) - with open(full_nmap_path, "a+") as log: - log.write(data) - return full_nmap_path + lib.core.common.write_to_log_file( + data, lib.core.settings.NMAP_LOG_FILE_PATH, + lib.core.settings.NMAP_FILENAME.format(self.ip) + ) def show_open_ports(self, json_data, sep="-" * 30): """ @@ -59,7 +58,7 @@ class NmapHook(object): print( "{}\nScanned: {} ({})\tStatus: {}\nProtocol: {}\n".format( sep, self.ip, - host if host is not "" or None or len(host) == 0 else "unknown", + host if host is not "" or None or not len(host) == 0 else "unknown", json_data[self.ip]["status"]["state"], "TCP" ) @@ -107,6 +106,8 @@ def perform_port_scan(url, scanner=NmapHook, **kwargs): lib.core.settings.logger.info(lib.core.settings.set_color( "attempting to find IP address for hostname '{}'...".format(url) )) + if "www" not in url: + url = "www.{}".format(url) try: found_ip_address = socket.gethostbyname(url) except socket.gaierror: diff --git a/lib/attacks/xss_scan/__init__.py b/lib/attacks/xss_scan/__init__.py index 24ca387..73aa0ed 100644 --- a/lib/attacks/xss_scan/__init__.py +++ b/lib/attacks/xss_scan/__init__.py @@ -136,6 +136,23 @@ def main_xss(start_url, proxy=None, agent=None, **kwargs): verbose = kwargs.get("verbose", False) batch = kwargs.get("batch", False) + question_msg = ( + "it appears that heuristic tests have shown this URL may not be a good " + "candidate to perform XSS tests on, would you like to continue anyways" + ) + if not batch: + if not lib.core.settings.URL_QUERY_REGEX.match(start_url): + question = lib.core.common.prompt( + question_msg, opts="yN" + ) + else: + question = lib.core.common.prompt( + question_msg, opts="yN", default="y" + ) + + if not question.lower().startswith("y"): + return + try: if tamper: lib.core.settings.logger.info(lib.core.settings.set_color( @@ -171,7 +188,7 @@ def main_xss(start_url, proxy=None, agent=None, **kwargs): payload = find_xss_script(url) try: result = scan_xss(url, proxy=proxy, agent=agent) - except requests.exceptions.ConnectionError: + except (requests.exceptions.ConnectionError, requests.exceptions.TooManyRedirects): lib.core.settings.logger.error(lib.core.settings.set_color( "payload '{}' caused a connection error, assuming no good and continuing...".format(payload), level=40 )) @@ -214,7 +231,7 @@ def main_xss(start_url, proxy=None, agent=None, **kwargs): lib.core.settings.logger.error(lib.core.settings.set_color( "host '{}' does not appear to be vulnerable to XSS attacks...".format(start_url) )) - question_msg = "would you like to keep the URL's saved for further testing" + question_msg = "would you like to keep the created URLs saved for further testing" if not batch: save = lib.core.common.prompt( question_msg, opts="yN" diff --git a/lib/core/common.py b/lib/core/common.py index 95dccc4..0a9ac40 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -19,11 +19,27 @@ import lib.core.settings # reference https://en.wikipedia.org/wiki/List_of_HTTP_status_codes STATUS_CODES = { - 200: "OK", 300: "multiple choices", 302: "not found", - 400: "bad request", 401: "unauthorized", 403: "forbidden", - 404: "not found", 405: "method not allowed", 500: "internal server error", - 501: "not implemented", 502: "bad gateway", 503: "service unavailable", - "other": "unexpected error code" + 100: "continue", 101: "switching protocols", 102: "processing", + 200: "OK", 201: "created", 202: "accepted", 203: "non-authoritative information", + 204: "no content", 205: "reset content", 206: "partial content", + 207: "multi-status", 208: "already reported", 226: "IM used", + 300: "multiple choices", 301: "moved permanently", 302: "not found", + 303: "see other", 304: "not modified", 305: "use proxy", + 306: "switch proxy", 308: "permanent redirect", + 400: "bad request", 401: "unauthorized", 402: "payment required", + 403: "forbidden", 404: "not found", 405: "method not allowed", + 406: "not acceptable", 407: "proxy authentication required", 408: "request timed out", + 409: "conflict", 410: "gone", 411: "length required", 412: "precondition failed", + 413: "payload to large", 414: "URI too long", 415: "unsupported media type", + 416: "range not satisfiable", 417: "expectation failed", 418: "im a teapot {EASTER EGG!}", + 421: "misdirected request", 422: "unprocesseable entity", 423: "locked", + 424: "failed dependency", 426: "upgrade requried", 428: "precondition required", + 429: "to many requests", 431: "request headers field too large", + 451: "unavailable for legal reasons", + 500: "internal server error", 501: "not implemented", 502: "bad gateway", + 503: "service unavailable", 504: "gateway timeout", 505: "HTTP version not supported", + 506: "variant also negotiable", 507: "insufficient storage", 508: "loop detected", + 510: "not extended", 511: "network authentication required", "other": "unexpected error code" } @@ -125,8 +141,7 @@ def write_to_log_file(data_to_write, path, filename, blacklist=False): ) skip_log_schema = ( "url-log", "blackwidow-log", "zeus-log", - "extracted", ".blacklist", "gist-match", - "sqli-sites" + "extracted", ".blacklist", "sqli-sites" ) to_search = filename.split("-")[0] amount = len([f for f in os.listdir(path) if to_search in f]) diff --git a/lib/core/settings.py b/lib/core/settings.py index 2908c0b..81f8dc1 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -46,7 +46,7 @@ CLONE = "https://github.com/ekultek/zeus-scanner.git" ISSUE_LINK = "https://github.com/ekultek/zeus-scanner/issues" # current version -VERSION = "1.3.11.{}".format(PATCH_ID) +VERSION = "1.3.12.{}".format(PATCH_ID) # colors to output depending on the version VERSION_TYPE_COLORS = {"dev": 33, "stable": 92, "other": 30} @@ -182,6 +182,9 @@ SQLI_SITES_FILEPATH = "{}/log/sqli-sites".format(os.getcwd()) # the current log file being used CURRENT_LOG_FILE_PATH = "{}/log".format(os.getcwd()) +# nmap scan log path +NMAP_LOG_FILE_PATH = "{}/log/nmap-scan-log".format(os.getcwd()) + # filename for sitemap log file SITEMAP_FILENAME = "{}-sitemap.xml" @@ -228,7 +231,7 @@ BLACKLIST_FILENAME = ".blacklist" BLACKWIDOW_FILENAME = "blackwidow-log-{}.log" # filename for nmap scans -NMAP_FILENAME = "nmap-scan-results-{}.json" +NMAP_FILENAME = "{}-nmap-scan-results.json" # github autohorization token path GITHUB_AUTH_PATH = "{}/etc/auths/git_auth".format(os.getcwd())