mirror of
https://github.com/Ekultek/Zeus-Scanner.git
synced 2026-03-11 08:55:51 +00:00
524 lines
No EOL
22 KiB
Python
Executable file
524 lines
No EOL
22 KiB
Python
Executable file
#!/usr/bin/env python
|
|
|
|
import os
|
|
import time
|
|
import optparse
|
|
import subprocess
|
|
import random
|
|
try:
|
|
import http.client as http_client # Python 3
|
|
except ImportError:
|
|
import httplib as http_client # Python 2
|
|
|
|
from var import blackwidow
|
|
from var.google_search import search
|
|
from lib.errors import InvalidInputProvided
|
|
from lib.attacks.admin_panel_finder import main
|
|
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 import (
|
|
nmap_scan,
|
|
sqlmap_scan,
|
|
intel_me
|
|
)
|
|
from lib.settings import (
|
|
setup,
|
|
BANNER,
|
|
start_up,
|
|
shutdown,
|
|
logger,
|
|
set_color,
|
|
get_latest_log_file,
|
|
grab_random_agent,
|
|
CURRENT_LOG_FILE_PATH,
|
|
AUTHORIZED_SEARCH_ENGINES,
|
|
URL_LOG_PATH,
|
|
SPIDER_LOG_PATH,
|
|
replace_http,
|
|
prompt,
|
|
get_random_dork,
|
|
update_zeus,
|
|
VERSION_STRING,
|
|
URL_REGEX, URL_QUERY_REGEX,
|
|
NMAP_MAN_PAGE_URL,
|
|
SQLMAP_MAN_PAGE_URL
|
|
)
|
|
|
|
if __name__ == "__main__":
|
|
|
|
parser = optparse.OptionParser(usage="{} -d|l|s|b DORK|FILE|URL [ATTACKS] [S-E] [--OPTS]".format(
|
|
os.path.basename(__file__)
|
|
))
|
|
|
|
# mandatory options
|
|
mandatory = optparse.OptionGroup(parser, "Mandatory Options",
|
|
"These options have to be used in order for Zeus to run")
|
|
mandatory.add_option("-d", "--dork", dest="dorkToUse", metavar="DORK",
|
|
help="Specify a singular Google dork to use for queries")
|
|
mandatory.add_option("-l", "--dork-list", dest="dorkFileToUse", metavar="FILE-PATH",
|
|
help="Specify a file full of dorks to run through"),
|
|
mandatory.add_option("-r", "--rand-dork", dest="useRandomDork", action="store_true",
|
|
help="Use a random dork from the etc/dorks.txt file to perform the scan")
|
|
mandatory.add_option("-b", "--blackwidow", dest="spiderWebSite", metavar="URL",
|
|
help="Spider a single webpage for all available URL's")
|
|
|
|
# attack options
|
|
attacks = optparse.OptionGroup(parser, "Attack arguments",
|
|
"These arguments will give you the choice on how you want to check the websites")
|
|
attacks.add_option("-s", "--sqli", dest="runSqliScan", action="store_true",
|
|
help="Run a Sqlmap SQLi scan on the discovered URL's")
|
|
attacks.add_option("-p", "--port-scan", dest="runPortScan", action="store_true",
|
|
help="Run a Nmap port scan on the discovered URL's")
|
|
attacks.add_option("-i", "--intel-check", dest="intelCheck", action="store_true",
|
|
help="Check if a URL's host is exploitable via Intel ME AMT (CVE-2017-5689)")
|
|
attacks.add_option("-a", "--admin-panel", dest="adminPanelFinder", action="store_true",
|
|
help="Search for the websites admin panel")
|
|
attacks.add_option("-x", "--xss-scan", dest="runXssScan", action="store_true",
|
|
help="Run an XSS scan on the found URL's")
|
|
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'")
|
|
attacks.add_option("--nmap-args", dest="nmapArguments", metavar="NMAP-ARGS",
|
|
help="Pass the arguments to send to the nmap API within quotes & "
|
|
"separated by a pipe. IE '-O|-p 445, 1080'")
|
|
attacks.add_option("--auto-start", dest="autoStartSqlmap", action="store_true",
|
|
help="Attempt to automatically find sqlmap on your system")
|
|
attacks.add_option("--search-here", dest="givenSearchPath", metavar="PATH-TO-START",
|
|
help="Start searching for sqlmap in this given path")
|
|
attacks.add_option("--show-sqlmap", dest="showSqlmapArguments", action="store_true",
|
|
help="Show the arguments that the sqlmap API understands")
|
|
attacks.add_option("--show-nmap", dest="showNmapArgs", action="store_true",
|
|
help="Show the arguments that nmap understands")
|
|
attacks.add_option("-P", "--show-possibles", dest="showAllConnections", action="store_true",
|
|
help="Show all connections made during the admin panel search")
|
|
attacks.add_option("--run-all", dest="runAllXssPayloads", action="store_true",
|
|
help="Run every loaded XSS payload")
|
|
|
|
# search engine options
|
|
engines = optparse.OptionGroup(parser, "Search engine arguments",
|
|
"Arguments to change the search engine used (default is Google)")
|
|
engines.add_option("-D", "--search-engine-ddg", dest="useDDG", action="store_true",
|
|
help="Use DuckDuckGo as the search engine")
|
|
engines.add_option("-B", "--search-engine-bing", dest="useBing", action="store_true",
|
|
help="Use Bing as the search engine")
|
|
engines.add_option("-A", "--search-engine-aol", dest="useAOL", action="store_true",
|
|
help="Use AOL as the search engine")
|
|
|
|
# obfuscation options
|
|
anon = optparse.OptionGroup(parser, "Anonymity arguments",
|
|
"Arguments that help with anonymity and hiding identity")
|
|
anon.add_option("--proxy", dest="proxyConfig", metavar="PROXY-STRING",
|
|
help="Use a proxy to do the scraping, will not auto configure to the API's")
|
|
anon.add_option("--proxy-file", dest="proxyFileRand", metavar="FILE-PATH",
|
|
help="Grab a random proxy from a given file of proxies")
|
|
anon.add_option("--random-agent", dest="useRandomAgent", action="store_true",
|
|
help="Use a random user-agent from the etc/agents.txt file")
|
|
anon.add_option("--agent", dest="usePersonalAgent", metavar="USER-AGENT",
|
|
help="Use your own personal user-agent")
|
|
|
|
# miscellaneous options
|
|
misc = optparse.OptionGroup(parser, "Misc Options",
|
|
"These options affect how the program will run")
|
|
misc.add_option("--verbose", dest="runInVerbose", action="store_true",
|
|
help="Run the application in verbose mode (more output)")
|
|
misc.add_option("--show-requests", dest="showRequestInfo", action="store_true",
|
|
help="Show all HTTP requests made by the application")
|
|
misc.add_option("--batch", dest="runInBatch", action="store_true",
|
|
help="Skip the questions and run in default batch mode")
|
|
misc.add_option("--update", dest="updateZeus", action="store_true",
|
|
help="Update to the latest development version")
|
|
misc.add_option("--hide", dest="hideBanner", action="store_true",
|
|
help="Hide the banner during running")
|
|
misc.add_option("--version", dest="showCurrentVersion", action="store_true",
|
|
help="Show the current version and exit")
|
|
|
|
parser.add_option_group(mandatory)
|
|
parser.add_option_group(attacks)
|
|
parser.add_option_group(anon)
|
|
parser.add_option_group(engines)
|
|
parser.add_option_group(misc)
|
|
|
|
opt, _ = parser.parse_args()
|
|
|
|
if opt.showCurrentVersion:
|
|
print(VERSION_STRING)
|
|
exit(0)
|
|
|
|
# run the setup on the program
|
|
setup(verbose=opt.runInVerbose)
|
|
|
|
if not opt.hideBanner:
|
|
print(BANNER)
|
|
|
|
start_up()
|
|
|
|
if opt.showSqlmapArguments:
|
|
logger.info(set_color(
|
|
"there are a total of {} arguments understood by sqlmap API, "
|
|
"they include:".format(len(SQLMAP_API_OPTIONS))
|
|
))
|
|
print("\n")
|
|
for arg in SQLMAP_API_OPTIONS:
|
|
print(
|
|
"[*] {}".format(arg)
|
|
)
|
|
print("\n")
|
|
logger.info(set_color(
|
|
"for more information about sqlmap arguments, see here '{}'...".format(
|
|
SQLMAP_MAN_PAGE_URL
|
|
)
|
|
))
|
|
shutdown()
|
|
|
|
if opt.showNmapArgs:
|
|
logger.info(set_color(
|
|
"there are a total of {} arguments understood by nmap, they include:".format(
|
|
len(NMAP_API_OPTS)
|
|
)
|
|
))
|
|
print("\n")
|
|
for arg in NMAP_API_OPTS:
|
|
print(
|
|
"[*] {}".format(arg)
|
|
)
|
|
print("\n")
|
|
logger.info(set_color(
|
|
"for more information on what the arguments do please see here '{}'...".format(
|
|
NMAP_MAN_PAGE_URL
|
|
)
|
|
))
|
|
shutdown()
|
|
|
|
# update the program
|
|
if opt.updateZeus:
|
|
logger.info(set_color(
|
|
"update in progress..."
|
|
))
|
|
update_zeus()
|
|
shutdown()
|
|
|
|
|
|
def __find_running_opts():
|
|
"""
|
|
display the running options if verbose is used
|
|
"""
|
|
opts_being_used = []
|
|
for o, v in opt.__dict__.items():
|
|
if v is not None:
|
|
opts_being_used.append((o, v))
|
|
return dict(opts_being_used)
|
|
|
|
|
|
if opt.runInVerbose:
|
|
being_run = __find_running_opts()
|
|
logger.debug(set_color(
|
|
"running with options '{}'...".format(being_run), level=10
|
|
))
|
|
|
|
logger.info(set_color(
|
|
"log file being saved to '{}'...".format(get_latest_log_file(CURRENT_LOG_FILE_PATH))
|
|
))
|
|
|
|
if opt.showRequestInfo:
|
|
logger.debug(set_color(
|
|
"showing all HTTP requests because --show-requests flag was used...", level=10
|
|
))
|
|
http_client.HTTPConnection.debuglevel = 1
|
|
|
|
|
|
def __config_headers():
|
|
"""
|
|
configure the request headers, this will configure user agents and proxies
|
|
"""
|
|
if opt.proxyConfig is not None:
|
|
proxy = opt.proxyConfig
|
|
elif opt.proxyFileRand is not None:
|
|
if opt.runInVerbose:
|
|
logger.debug(set_color(
|
|
"loading random proxy from '{}'...".format(opt.proxyFileRand), level=10
|
|
))
|
|
with open(opt.proxyFileRand) as proxies:
|
|
possible = proxies.readlines()
|
|
proxy = random.choice(possible).strip()
|
|
else:
|
|
proxy = None
|
|
if opt.usePersonalAgent is not None:
|
|
agent = opt.usePersonalAgent
|
|
elif opt.useRandomAgent:
|
|
agent = grab_random_agent(verbose=opt.runInVerbose)
|
|
else:
|
|
agent = None
|
|
return proxy, agent
|
|
|
|
|
|
def __config_search_engine(verbose=False):
|
|
"""
|
|
configure the search engine if a one different from google is given
|
|
"""
|
|
non_default_msg = "specified to use non-default search engine..."
|
|
if opt.useDDG:
|
|
if verbose:
|
|
logger.debug(set_color(
|
|
"using DuckDuckGo as the search engine...", level=10
|
|
))
|
|
logger.info(set_color(
|
|
non_default_msg
|
|
))
|
|
se = AUTHORIZED_SEARCH_ENGINES["duckduckgo"]
|
|
elif opt.useAOL:
|
|
if verbose:
|
|
logger.debug(set_color(
|
|
"using AOL as the search engine...", level=10
|
|
))
|
|
logger.info(set_color(
|
|
non_default_msg
|
|
))
|
|
se = AUTHORIZED_SEARCH_ENGINES["aol"]
|
|
else:
|
|
if verbose:
|
|
logger.debug(set_color(
|
|
"using default search engine (Google)...", level=10
|
|
))
|
|
logger.info(set_color(
|
|
"using default search engine..."
|
|
))
|
|
se = AUTHORIZED_SEARCH_ENGINES["google"]
|
|
return se
|
|
|
|
|
|
def __create_arguments(sqlmap=False, nmap=False):
|
|
"""
|
|
create the sqlmap arguments (a list of tuples) that will be passed to the API
|
|
"""
|
|
logger.info(set_color(
|
|
"creating arguments for {}...".format("sqlmap" if sqlmap else "nmap")
|
|
))
|
|
retval = []
|
|
splitter = {"sqlmap": ",", "nmap": "|"}
|
|
if sqlmap:
|
|
if opt.sqlmapArguments is not None:
|
|
for line in opt.sqlmapArguments.split(splitter["sqlmap"]):
|
|
to_use = line.strip().split(" ")
|
|
option = (to_use[0], to_use[1])
|
|
if to_use[0] in SQLMAP_API_OPTIONS:
|
|
retval.append(option)
|
|
else:
|
|
logger.warning(set_color(
|
|
"option '{}' is not recognized by sqlmap API, skipping...".format(option[0]),
|
|
level=30
|
|
))
|
|
elif nmap:
|
|
warning_msg = "option {} is not known by the nmap api, skipping..."
|
|
if opt.nmapArguments is not None:
|
|
for line in opt.nmapArguments.split(splitter["nmap"]):
|
|
try:
|
|
data = line.index(" ")
|
|
except:
|
|
data = None
|
|
pass
|
|
if data is not None:
|
|
argument = line[0:data]
|
|
if argument in NMAP_API_OPTS:
|
|
retval.append(line)
|
|
else:
|
|
logger.warning(set_color(
|
|
warning_msg.format(argument), level=30
|
|
))
|
|
else:
|
|
if line in NMAP_API_OPTS:
|
|
retval.append(line)
|
|
else:
|
|
logger.warning(set_color(
|
|
warning_msg.format(line), level=30
|
|
))
|
|
return retval
|
|
|
|
|
|
def __run_attacks(
|
|
url, sqlmap=False, nmap=False, intel=False, xss=False,
|
|
verbose=False, admin=False, given_path=None, auto=False, batch=False
|
|
):
|
|
"""
|
|
run the attacks if any are requested
|
|
"""
|
|
if not batch:
|
|
question = prompt(
|
|
"would you like to process found URL: '{}'".format(url), opts=["y", "N"]
|
|
)
|
|
else:
|
|
question = "y"
|
|
|
|
if question.lower().startswith("y"):
|
|
if sqlmap:
|
|
return sqlmap_scan.sqlmap_scan_main(url.strip(), verbose=verbose, opts=__create_arguments(sqlmap=True),
|
|
auto_search=auto, given_path=given_path)
|
|
elif nmap:
|
|
url_ip_address = replace_http(url.strip())
|
|
return nmap_scan.perform_port_scan(url_ip_address, verbose=verbose, opts=__create_arguments(nmap=True))
|
|
elif intel:
|
|
url_ip_address = replace_http(url.strip())
|
|
return intel_me.intel_amt_main(url_ip_address, proxy=proxy_to_use, verbose=verbose)
|
|
elif admin:
|
|
main(url, show=opt.showAllConnections, verbose=verbose)
|
|
elif xss:
|
|
main_xss(url, verbose=verbose, proxy=proxy_to_use, agent=agent_to_use, try_all=opt.runAllXssPayloads)
|
|
else:
|
|
pass
|
|
else:
|
|
logger.warning(set_color(
|
|
"skipping '{}'...".format(url), level=30
|
|
))
|
|
|
|
|
|
proxy_to_use, agent_to_use = __config_headers()
|
|
search_engine = __config_search_engine(verbose=opt.runInVerbose)
|
|
|
|
try:
|
|
# use a personal dork as the query
|
|
if opt.dorkToUse is not None:
|
|
logger.info(set_color(
|
|
"starting dork scan with query '{}'...".format(opt.dorkToUse)
|
|
))
|
|
try:
|
|
search.parse_search_results(
|
|
opt.dorkToUse, search_engine, verbose=opt.runInVerbose, proxy=proxy_to_use,
|
|
agent=agent_to_use
|
|
)
|
|
except Exception as e:
|
|
logger.exception(set_color(
|
|
"ran into exception '{}'...".format(e), level=50
|
|
))
|
|
pass
|
|
|
|
urls_to_use = get_latest_log_file(URL_LOG_PATH)
|
|
if opt.runSqliScan or opt.runPortScan or opt.intelCheck or opt.adminPanelFinder or opt.runXssScan:
|
|
with open(urls_to_use) as urls:
|
|
for url in urls.readlines():
|
|
__run_attacks(
|
|
url.strip(),
|
|
sqlmap=opt.runSqliScan, nmap=opt.runPortScan, intel=opt.intelCheck, xss=opt.runXssScan,
|
|
admin=opt.adminPanelFinder, given_path=opt.givenSearchPath,
|
|
auto=opt.autoStartSqlmap, verbose=opt.runInVerbose, batch=opt.runInBatch
|
|
)
|
|
|
|
# use a file full of dorks as the queries
|
|
elif opt.dorkFileToUse is not None:
|
|
with open(opt.dorkFileToUse) as dorks:
|
|
for dork in dorks.readlines():
|
|
dork = dork.strip()
|
|
logger.info(set_color(
|
|
"starting dork scan with query '{}'...".format(dork)
|
|
))
|
|
try:
|
|
search.parse_search_results(
|
|
dork, search_engine, verbose=opt.runInVerbose, proxy=proxy_to_use,
|
|
agent=agent_to_use
|
|
)
|
|
except Exception as e:
|
|
logger.exception(set_color(
|
|
"ran into exception '{}'...".format(e), level=50
|
|
))
|
|
pass
|
|
|
|
urls_to_use = get_latest_log_file(URL_LOG_PATH)
|
|
if opt.runSqliScan or opt.runPortScan or opt.intelCheck or opt.adminPanelFinder or opt.runXssScan:
|
|
with open(urls_to_use) as urls:
|
|
for url in urls.readlines():
|
|
__run_attacks(
|
|
url.strip(),
|
|
sqlmap=opt.runSqliScan, nmap=opt.runPortScan, intel=opt.intelCheck, xss=opt.runXssScan,
|
|
admin=opt.adminPanelFinder, given_path=opt.givenSearchPath,
|
|
auto=opt.autoStartSqlmap, verbose=opt.runInVerbose, batch=opt.runInBatch
|
|
)
|
|
|
|
# use a random dork as the query
|
|
elif opt.useRandomDork:
|
|
random_dork = get_random_dork().strip()
|
|
if opt.runInVerbose:
|
|
logger.debug(set_color(
|
|
"choosing random dork from etc/dorks.txt...", level=10
|
|
))
|
|
logger.info(set_color(
|
|
"using random dork '{}' as the search query...".format(random_dork)
|
|
))
|
|
try:
|
|
search.parse_search_results(
|
|
random_dork, search_engine, verbose=opt.runInVerbose,
|
|
proxy=proxy_to_use, agent=agent_to_use
|
|
)
|
|
urls_to_use = get_latest_log_file(URL_LOG_PATH)
|
|
if opt.runSqliScan or opt.runPortScan or opt.intelCheck or opt.adminPanelFinder or opt.runXssScan:
|
|
with open(urls_to_use) as urls:
|
|
for url in urls.readlines():
|
|
__run_attacks(
|
|
url.strip(),
|
|
sqlmap=opt.runSqliScan, nmap=opt.runPortScan, intel=opt.intelCheck, xss=opt.runXssScan,
|
|
admin=opt.adminPanelFinder, given_path=opt.givenSearchPath,
|
|
auto=opt.autoStartSqlmap, verbose=opt.runInVerbose, batch=opt.runInBatch
|
|
)
|
|
|
|
except Exception as e:
|
|
logger.exception(set_color(
|
|
"ran into exception '{}' and cannot continue, saved to current log file...".format(e),
|
|
level=50
|
|
))
|
|
|
|
elif opt.spiderWebSite:
|
|
if not URL_REGEX.match(opt.spiderWebSite):
|
|
err_msg = "URL did not match a true URL{}..."
|
|
if "www" in opt.spiderWebSite:
|
|
err_msg = err_msg.format(" issue seems to be that 'www' is in the URL, "
|
|
"replace with http(s)://")
|
|
else:
|
|
err_msg = err_msg.format("")
|
|
raise InvalidInputProvided(
|
|
err_msg
|
|
)
|
|
else:
|
|
if URL_QUERY_REGEX.match(opt.spiderWebSite):
|
|
is_sure = prompt(
|
|
"it is recomened to not use a URL that has a GET(query) parameter in it, "
|
|
"would you like to continue", "yN"
|
|
)
|
|
if is_sure.lower().startswith("y"):
|
|
pass
|
|
else:
|
|
shutdown()
|
|
|
|
blackwidow.blackwidow_main(opt.spiderWebSite, agent=agent_to_use, proxy=proxy_to_use, verbose=opt.runInVerbose)
|
|
|
|
urls_to_use = get_latest_log_file(SPIDER_LOG_PATH)
|
|
if opt.runSqliScan or opt.runPortScan or opt.intelCheck or opt.adminPanelFinder or opt.runXssScan:
|
|
with open(urls_to_use) as urls:
|
|
for url in urls.readlines():
|
|
__run_attacks(
|
|
url.strip(),
|
|
sqlmap=opt.runSqliScan, nmap=opt.runPortScan, intel=opt.intelCheck, xss=opt.runXssScan,
|
|
admin=opt.adminPanelFinder, given_path=opt.givenSearchPath,
|
|
auto=opt.autoStartSqlmap, verbose=opt.runInVerbose, batch=opt.runInBatch
|
|
)
|
|
|
|
else:
|
|
logger.critical(set_color(
|
|
"failed to provide a mandatory argument, you will be redirected to the help menu...", level=50
|
|
))
|
|
time.sleep(2)
|
|
subprocess.call("python zeus.py --help", shell=True)
|
|
|
|
except KeyboardInterrupt:
|
|
logger.error(set_color(
|
|
"user aborted process...", level=40
|
|
))
|
|
except UnboundLocalError:
|
|
logger.warning(set_color(
|
|
"do not interrupt the browser when selenium is running, "
|
|
"it will cause Zeus to crash...", level=30
|
|
))
|
|
except Exception as e:
|
|
logger.exception(set_color(
|
|
"ran into exception '{}' exception has been saved to log file...".format(e), level=50
|
|
))
|
|
|
|
shutdown() |