mirror of
https://github.com/Ekultek/Zeus-Scanner.git
synced 2026-03-11 08:55:51 +00:00
created a clickjacking scanner that will test a page for an X-Frame-Options header, if the header is not there, then it will create a basic HTML page with that URL as an iframe
This commit is contained in:
parent
d1adbcdc10
commit
bc335fa2d3
6 changed files with 142 additions and 9 deletions
|
|
@ -1,4 +1,4 @@
|
|||
7fa426efc9d5b26d93101c0058840788 ./zeus.py
|
||||
b100d6428f04f18100e9358688004abd ./zeus.py
|
||||
6ad5f22ec4a6f8324bfb1b01ab6d51ec ./etc/scripts/cleanup.sh
|
||||
155c9482f690f1482f324a7ffd8b8098 ./etc/scripts/fix_pie.sh
|
||||
0e435c641bc636ac0b3d54e032d9cf6a ./etc/scripts/install_nmap.sh
|
||||
|
|
@ -9,6 +9,7 @@
|
|||
82cc68f46539d0255f7ce14cd86cd49b ./etc/link_ext.txt
|
||||
a3ee2d4610056c6fe270c2a74dda49f9 ./etc/dorks.txt
|
||||
b34aacdcb683a2de649c002601f53746 ./etc/xss_payloads.txt
|
||||
f914fafb99953a9124295b381be2954b .etc/clickjacking_test_page.html
|
||||
d41d8cd98f00b204e9800998ecf8427e ./bin/__init__.py
|
||||
ff2511effe21aa36002f37ed9bfe47ec ./bin/unzip_gecko.py
|
||||
dc1eb4ebe0f372af48b5a9c107ebc68d ./bin/drivers/geckodriver-v0.18.0-linux32.tar.gz
|
||||
|
|
@ -40,11 +41,12 @@ e2b494ba257444ed4a9a8a554dcbe250 ./lib/attacks/whois_lookup/whois.py
|
|||
27358f26bda30d7356143c3ea1fa99c5 ./lib/attacks/nmap_scan/__init__.py
|
||||
216999fa0e84866d5c1d96d5676034e4 ./lib/attacks/nmap_scan/nmap_opts.py
|
||||
f746d2867f493104a78d0540cf50c03f ./lib/attacks/intel_me/__init__.py
|
||||
49c88c6927a141a688d3fc0c7c101019 .lib/attacks/clickjacking_scan/__init__.py
|
||||
1faa2b5dfad6eb538bbfe42942d2a9da ./lib/core/errors.py
|
||||
d41d8cd98f00b204e9800998ecf8427e ./lib/core/__init__.py
|
||||
97bfe118adfdfc3ef02c5dca4c0aec62 ./lib/core/settings.py
|
||||
1781e9963d34604b626b6fe3db513bc7 ./lib/core/settings.py
|
||||
d41d8cd98f00b204e9800998ecf8427e ./var/google_search/__init__.py
|
||||
2d984415adc457061e1757cbd79ea12b ./var/google_search/search.py
|
||||
914ac7cf2e216ca878a5f711a71290a8 ./var/google_search/search.py
|
||||
d41d8cd98f00b204e9800998ecf8427e ./var/__init__.py
|
||||
d41d8cd98f00b204e9800998ecf8427e ./var/auto_issue/__init__.py
|
||||
4506850a02aa18e12bef4efeb760ad9e ./var/auto_issue/github.py
|
||||
|
|
|
|||
5
etc/clickjacking_test_page.html
Normal file
5
etc/clickjacking_test_page.html
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<html>
|
||||
<body>
|
||||
<iframe src="{}" width="" height=""></iframe>
|
||||
</body>
|
||||
</html>
|
||||
112
lib/attacks/clickjacking_scan/__init__.py
Normal file
112
lib/attacks/clickjacking_scan/__init__.py
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
import requests
|
||||
|
||||
import lib.core.settings
|
||||
import var.auto_issue.github
|
||||
|
||||
|
||||
class ClickJackingScanner(object):
|
||||
|
||||
def __init__(self, url):
|
||||
self.url = url
|
||||
self.safe = "X-Frame-Options"
|
||||
self.html = open(lib.core.settings.CLICKJACKING_TEST_PAGE_PATH).read()
|
||||
|
||||
def generate_html(self):
|
||||
"""
|
||||
generate the HTML page if the clicking test was successfully completed
|
||||
"""
|
||||
return self.html.format(self.url)
|
||||
|
||||
def extract_and_test_headers(self, **kwargs):
|
||||
"""
|
||||
extract the headers from the url given to test if they contain the correct protection
|
||||
against clickjacking
|
||||
"""
|
||||
proxy = kwargs.get("proxy", None)
|
||||
agent = kwargs.get("agent", None)
|
||||
forward = kwargs.get("forward", None)
|
||||
if forward is not None:
|
||||
ip_addrs = lib.core.settings.create_random_ip()
|
||||
headers = {
|
||||
"user-agent": agent,
|
||||
"X-Forwarded-From": "{}, {}, {}".format(
|
||||
ip_addrs[0], ip_addrs[1], ip_addrs[2]
|
||||
),
|
||||
"Connection": "close"
|
||||
}
|
||||
else:
|
||||
headers = {
|
||||
"user-agent": agent,
|
||||
"Connection": "close"
|
||||
}
|
||||
req = requests.get(self.url, headers=headers, proxies=lib.core.settings.proxy_string_to_dict(proxy))
|
||||
headers = req.headers
|
||||
if self.safe in headers:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def clickjacking_main(url, **kwargs):
|
||||
"""
|
||||
main function for the clickjacking scan
|
||||
"""
|
||||
agent = kwargs.get("agent", None)
|
||||
proxy = kwargs.get("proxy", None)
|
||||
forward = kwargs.get("forward", None)
|
||||
verbose = kwargs.get("verbose", False)
|
||||
batch = kwargs.get("batch", False)
|
||||
|
||||
if not batch:
|
||||
if lib.core.settings.URL_QUERY_REGEX.match(url):
|
||||
question = lib.core.settings.prompt(
|
||||
"it is recommended to use a URL without a GET(query) parameter, "
|
||||
"heuristic testing has detected that the URL provided contains a "
|
||||
"GET(query) parameter in it, would you like to continue", opts="yN"
|
||||
)
|
||||
if question.lower().startswith("n"):
|
||||
lib.core.settings.logger.info(lib.core.settings.set_color(
|
||||
"automatically removing all queries from URL..."
|
||||
))
|
||||
url = "http://{}".format(lib.core.settings.replace_http(url, complete=True))
|
||||
|
||||
scanner = ClickJackingScanner(url)
|
||||
|
||||
if verbose:
|
||||
lib.core.settings.logger.debug(lib.core.settings.set_color(
|
||||
"generating HTML...", level=10
|
||||
))
|
||||
|
||||
data = scanner.generate_html()
|
||||
|
||||
if verbose:
|
||||
lib.core.settings.logger.debug(lib.core.settings.set_color(
|
||||
"HTML generated successfully...", level=10
|
||||
))
|
||||
print("{}\n{}\n{}".format("-" * 30, data, "-" * 30))
|
||||
|
||||
try:
|
||||
results = scanner.extract_and_test_headers(agent=agent, proxy=proxy, forward=forward)
|
||||
|
||||
if results:
|
||||
lib.core.settings.logger.info(lib.core.settings.set_color(
|
||||
"it appears that provided URL '{}' is vulnerable to clickjacking, writing "
|
||||
"to HTML file...".format(url)
|
||||
))
|
||||
lib.core.settings.write_to_log_file(
|
||||
data,
|
||||
lib.core.settings.CLICKJACKING_RESULTS_PATH,
|
||||
"{}-clickjacking.html".format(lib.core.settings.replace_http(url))
|
||||
)
|
||||
else:
|
||||
lib.core.settings.logger.error(lib.core.settings.set_color(
|
||||
"provided URL '{}' seems to have the correct protection from clickjacking...".format(
|
||||
url
|
||||
), level=40
|
||||
))
|
||||
|
||||
except Exception as e: # until I figure out the errors, we'll just make issues about them
|
||||
lib.core.settings.logger.exception(lib.core.settings.set_color(
|
||||
"Zeus failed to process the clickjacking test and received "
|
||||
"error code '{}'...".format(e), level=50
|
||||
))
|
||||
var.auto_issue.github.request_issue_creation()
|
||||
|
|
@ -41,7 +41,7 @@ PATCH_ID = str(subprocess.check_output(["git", "rev-parse", "origin/master"]))[:
|
|||
# clone link
|
||||
CLONE = "https://github.com/ekultek/zeus-scanner.git"
|
||||
# current version <major.minor.commit.patch ID>
|
||||
VERSION = "1.1.12.{}".format(PATCH_ID)
|
||||
VERSION = "1.1.13".format(PATCH_ID)
|
||||
# colors to output depending on the version
|
||||
VERSION_TYPE_COLORS = {"dev": 33, "stable": 92, "other": 30}
|
||||
# version string formatting
|
||||
|
|
@ -83,10 +83,14 @@ CLEANUP_TOOL_PATH = "{}/etc/scripts/cleanup.sh".format(os.getcwd())
|
|||
LAUNCH_SQLMAP_API_TOOL = "{}/etc/scripts/launch_sqlmap_api.sh".format(os.getcwd())
|
||||
# path to nmap installer
|
||||
NMAP_INSTALLER_TOOL = "{}/etc/scripts/install_nmap.sh".format(os.getcwd())
|
||||
# clickjacking HTML test page path
|
||||
CLICKJACKING_TEST_PAGE_PATH = "{}/etc/clickjacking_test_page.html".format(os.getcwd())
|
||||
# path to check if the program has been executed or not
|
||||
EXECUTED_PATH = "{}/bin/executed.txt".format(os.getcwd())
|
||||
# paths to sqlmap and nmap
|
||||
TOOL_PATHS = "{}/bin/paths/path_config.ini".format(os.getcwd())
|
||||
# path to write the HTML in
|
||||
CLICKJACKING_RESULTS_PATH = "{}/log/clickjacking-log".format(os.getcwd())
|
||||
# the log for found admin pages on a site
|
||||
ADMIN_PAGE_FILE_PATH = "{}/log/admin-page-log".format(os.getcwd())
|
||||
# path to the sitemap log file
|
||||
|
|
@ -465,7 +469,7 @@ def write_to_log_file(data_to_write, path, filename):
|
|||
log.write(etree.tostring(data_to_write, pretty_print=True))
|
||||
except TypeError:
|
||||
logger.warning(set_color(
|
||||
"unable to serialize XML, writing as plain text (usually means the file already exists)...",
|
||||
"unable to serialize data, writing as plain text (usually means the file already exists)...",
|
||||
level=30
|
||||
))
|
||||
log.write(data_to_write)
|
||||
|
|
|
|||
|
|
@ -275,7 +275,7 @@ def parse_search_results(query, url_to_search, verbose=False, **kwargs):
|
|||
ip_to_use = (create_random_ip(), create_random_ip(), create_random_ip())
|
||||
if verbose:
|
||||
logger.debug(set_color(
|
||||
"random IP address generated for headers '{}'...".format(ip_to_use), level=10
|
||||
"random IP addresses generated for headers '{}'...".format(ip_to_use), level=10
|
||||
))
|
||||
|
||||
headers = {
|
||||
|
|
|
|||
16
zeus.py
16
zeus.py
|
|
@ -19,6 +19,7 @@ from lib.attacks.xss_scan import main_xss
|
|||
from lib.attacks.nmap_scan.nmap_opts import NMAP_API_OPTS
|
||||
from lib.attacks.sqlmap_scan.sqlmap_opts import SQLMAP_API_OPTIONS
|
||||
from lib.attacks.whois_lookup.whois import whois_lookup_main
|
||||
from lib.attacks.clickjacking_scan import clickjacking_main
|
||||
|
||||
from lib.core.errors import (
|
||||
InvalidInputProvided,
|
||||
|
|
@ -92,6 +93,8 @@ if __name__ == "__main__":
|
|||
help="Run an XSS scan on the found URL's")
|
||||
attacks.add_option("-w", "--whois-lookup", dest="performWhoisLookup", action="store_true",
|
||||
help="Perform a WhoIs lookup on the provided domain")
|
||||
attacks.add_option("-c", "--clickjacking", dest="performClickjackingScan", action="store_true",
|
||||
help="Perform a clickjacking scan on a provided URL")
|
||||
attacks.add_option("--sqlmap-args", dest="sqlmapArguments", metavar="SQLMAP-ARGS",
|
||||
help="Pass the arguments to send to the sqlmap API within quotes & "
|
||||
"separated by a comma. IE 'dbms mysql, verbose 3, level 5'")
|
||||
|
|
@ -268,6 +271,7 @@ if __name__ == "__main__":
|
|||
admin = kwargs.get("admin", False)
|
||||
verbose = kwargs.get("verbose", False)
|
||||
whois = kwargs.get("whois", False)
|
||||
clickjacking = kwargs.get("clickjacking", False)
|
||||
batch = kwargs.get("batch", False)
|
||||
auto_start = kwargs.get("auto_start", False)
|
||||
|
||||
|
|
@ -277,7 +281,8 @@ if __name__ == "__main__":
|
|||
"xss": opt.runXssScan,
|
||||
"admin": opt.adminPanelFinder,
|
||||
"intel": opt.intelCheck,
|
||||
"whois": opt.performWhoisLookup
|
||||
"whois": opt.performWhoisLookup,
|
||||
"clickjacking": opt.performClickjackingScan
|
||||
}
|
||||
|
||||
enabled = set()
|
||||
|
|
@ -296,7 +301,7 @@ if __name__ == "__main__":
|
|||
|
||||
if not batch:
|
||||
question = prompt(
|
||||
"would you like to process found URL: '{}'gi".format(url), opts=["y", "N"]
|
||||
"would you like to process found URL: '{}'".format(url), opts=["y", "N"]
|
||||
)
|
||||
else:
|
||||
question = "y"
|
||||
|
|
@ -332,6 +337,9 @@ if __name__ == "__main__":
|
|||
whois_lookup_main(
|
||||
url, verbose=opt.runInVerbose
|
||||
)
|
||||
elif clickjacking:
|
||||
clickjacking_main(url, agent=agent_to_use, proxy=proxy_to_use,
|
||||
forward=opt.forwardedForRandomIP, batch=opt.runInBatch)
|
||||
else:
|
||||
pass
|
||||
else:
|
||||
|
|
@ -364,7 +372,8 @@ if __name__ == "__main__":
|
|||
options = [
|
||||
opt.runSqliScan, opt.runPortScan,
|
||||
opt.intelCheck, opt.adminPanelFinder,
|
||||
opt.runXssScan, opt.performWhoisLookup
|
||||
opt.runXssScan, opt.performWhoisLookup,
|
||||
opt.performClickjackingScan
|
||||
]
|
||||
if any(options):
|
||||
with open(urls_to_use) as urls:
|
||||
|
|
@ -374,6 +383,7 @@ if __name__ == "__main__":
|
|||
sqlmap=opt.runSqliScan, nmap=opt.runPortScan,
|
||||
intel=opt.intelCheck, xss=opt.runXssScan,
|
||||
whois=opt.performWhoisLookup, admin=opt.adminPanelFinder,
|
||||
clickjacking=opt.performClickjackingScan,
|
||||
verbose=opt.runInVerbose, batch=opt.runInBatch,
|
||||
auto_start=opt.autoStartSqlmap
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in a new issue