2017-09-07 17:54:16 +00:00
|
|
|
import json
|
2017-10-10 22:01:13 +00:00
|
|
|
import re
|
2017-10-13 18:15:46 +00:00
|
|
|
import subprocess
|
2017-10-25 21:32:27 +00:00
|
|
|
import shlex
|
2017-10-10 22:01:13 +00:00
|
|
|
|
2017-09-29 19:28:53 +00:00
|
|
|
try:
|
|
|
|
|
import urllib2 # python 2
|
|
|
|
|
except ImportError:
|
|
|
|
|
import urllib as urllib2 # python 3
|
2017-09-07 17:54:16 +00:00
|
|
|
|
|
|
|
|
import requests
|
|
|
|
|
|
2017-11-20 20:27:08 +00:00
|
|
|
import lib.core.common
|
2017-10-10 22:01:13 +00:00
|
|
|
import lib.core.settings
|
|
|
|
|
import lib.core.errors
|
2017-11-10 20:30:01 +00:00
|
|
|
import lib.attacks
|
2017-09-07 17:54:16 +00:00
|
|
|
|
2017-09-30 13:01:40 +00:00
|
|
|
from var.auto_issue.github import request_issue_creation
|
|
|
|
|
|
2017-09-07 17:54:16 +00:00
|
|
|
|
|
|
|
|
class SqlmapHook(object):
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
Sqlmap API hook, will process API requests, and output API data
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def __init__(self, to_scan, port=None, api_con="http://127.0.0.1:{}", default_port=8775):
|
|
|
|
|
self.to_scan = to_scan
|
2017-09-25 15:19:46 +00:00
|
|
|
self.port = port or default_port
|
2017-09-07 17:54:16 +00:00
|
|
|
self.headers = {"Content-Type": "application/json"}
|
|
|
|
|
self.connection = api_con.format(self.port)
|
|
|
|
|
self.commands = {
|
|
|
|
|
"init": "/task/new",
|
|
|
|
|
"id": "/admin/0/list",
|
|
|
|
|
"start": "/scan/{}/start",
|
|
|
|
|
"status": "/scan/{}/status",
|
|
|
|
|
"log": "/scan/{}/log"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def init_new_scan(self):
|
|
|
|
|
"""
|
|
|
|
|
create a new API scan
|
|
|
|
|
"""
|
|
|
|
|
new_scan_url = "{}{}".format(self.connection, self.commands["init"])
|
|
|
|
|
return requests.get(new_scan_url, params=self.headers)
|
|
|
|
|
|
2017-10-06 02:21:51 +00:00
|
|
|
def get_scan_id(self, split_by=16):
|
2017-09-07 17:54:16 +00:00
|
|
|
"""
|
|
|
|
|
get the ID of the current API scan
|
|
|
|
|
"""
|
2017-10-07 13:09:16 +00:00
|
|
|
current_scan_id = None
|
2017-09-07 17:54:16 +00:00
|
|
|
id_re = re.compile(r"[a-fA-F0-9]{16}")
|
|
|
|
|
api_id_url = "{}{}".format(self.connection, self.commands["id"])
|
|
|
|
|
req = requests.get(api_id_url)
|
|
|
|
|
to_check = str(json.loads(req.content)["tasks"]).lower()
|
2017-10-07 13:09:16 +00:00
|
|
|
found = ''.join(id_re.findall(to_check))
|
|
|
|
|
if len(found) > 16:
|
2017-11-06 18:25:53 +00:00
|
|
|
# split the found ID by 16 characters each time one is found to be over 16 characters
|
|
|
|
|
# IE ['abcdee345593fffa', '2222aaa449837cc9']
|
|
|
|
|
# if any of these items are not in the already used container, then chances are that's the
|
|
|
|
|
# item we're looking for.
|
|
|
|
|
# this will also allow you to go back to the same item more then once.
|
2017-10-07 13:09:16 +00:00
|
|
|
data_found = [found[i:i+split_by] for i in range(0, len(found), split_by)]
|
|
|
|
|
for item in data_found:
|
2017-10-10 22:01:13 +00:00
|
|
|
if item not in lib.core.settings.ALREADY_USED:
|
|
|
|
|
lib.core.settings.ALREADY_USED.add(item)
|
2017-10-07 13:09:16 +00:00
|
|
|
current_scan_id = item
|
|
|
|
|
else:
|
2017-10-10 22:01:13 +00:00
|
|
|
lib.core.settings.ALREADY_USED.add(found)
|
2017-10-07 13:09:16 +00:00
|
|
|
current_scan_id = found
|
2017-10-06 02:21:51 +00:00
|
|
|
return current_scan_id
|
2017-09-07 17:54:16 +00:00
|
|
|
|
|
|
|
|
def start_scan(self, api_id, opts=None):
|
|
|
|
|
"""
|
|
|
|
|
start the API scan
|
|
|
|
|
"""
|
|
|
|
|
start_scan_url = "{}{}".format(self.connection, self.commands["start"].format(api_id))
|
|
|
|
|
data_dict = {"url": self.to_scan}
|
|
|
|
|
if opts is not None:
|
|
|
|
|
for i in range(0, len(opts)):
|
2017-11-06 18:25:53 +00:00
|
|
|
# if the options are passed they will be placed as a dict
|
|
|
|
|
# IE {'level': 5, 'risk': 3}
|
|
|
|
|
# from there they will be added into the post data dict what this
|
|
|
|
|
# will accomplish is that it will take precedence over the already
|
|
|
|
|
# set data on the sqlmap API client and replace that data with the
|
|
|
|
|
# data that is provided.
|
|
|
|
|
# IE
|
|
|
|
|
# {
|
|
|
|
|
# 'level': 1,
|
|
|
|
|
# 'risk': 1,
|
|
|
|
|
# }
|
|
|
|
|
# will become
|
|
|
|
|
# {
|
|
|
|
|
# 'level': '5',
|
|
|
|
|
# 'risk': '3',
|
|
|
|
|
# }
|
2017-09-07 17:54:16 +00:00
|
|
|
data_dict[opts[i][0]] = opts[i][1]
|
|
|
|
|
post_data = json.dumps(data_dict)
|
|
|
|
|
req = urllib2.Request(start_scan_url, data=post_data, headers=self.headers)
|
|
|
|
|
return urllib2.urlopen(req)
|
|
|
|
|
|
|
|
|
|
def show_sqlmap_log(self, api_id):
|
|
|
|
|
"""
|
|
|
|
|
show the sqlmap log during the API scan
|
|
|
|
|
"""
|
|
|
|
|
running_status_url = "{}{}".format(self.connection, self.commands["status"].format(api_id))
|
|
|
|
|
running_log_url = "{}{}".format(self.connection, self.commands["log"].format(api_id))
|
|
|
|
|
status_req = requests.get(running_status_url)
|
|
|
|
|
status_json = json.loads(status_req.content)
|
|
|
|
|
current_status = status_json["status"]
|
|
|
|
|
if current_status != "running":
|
2017-10-10 22:01:13 +00:00
|
|
|
raise lib.core.errors.SqlmapFailedStart(
|
2017-09-07 17:54:16 +00:00
|
|
|
"sqlmap API failed to start the run, check the client and see what "
|
|
|
|
|
"the problem is and try again..."
|
|
|
|
|
)
|
|
|
|
|
already_displayed = set()
|
|
|
|
|
while current_status == "running":
|
2017-11-06 18:25:53 +00:00
|
|
|
# while the current status evaluates to `running`
|
|
|
|
|
# we can load the JSON data and output the log information
|
|
|
|
|
# we will skip over information that has already been provided
|
|
|
|
|
# by using the already displayed container set.
|
|
|
|
|
# this will allow us to only output information that we
|
|
|
|
|
# have not seen yet.
|
2017-09-07 17:54:16 +00:00
|
|
|
current_status = json.loads(requests.get(running_status_url).content)["status"]
|
|
|
|
|
log_req = requests.get(running_log_url)
|
|
|
|
|
log_json = json.loads(log_req.content)
|
|
|
|
|
for i in range(0, len(log_json["log"])):
|
|
|
|
|
if log_json["log"][i]["message"] in already_displayed:
|
|
|
|
|
pass
|
|
|
|
|
else:
|
|
|
|
|
print(
|
|
|
|
|
"sqlmap> [{} {}] {}".format(
|
|
|
|
|
log_json["log"][i]["time"],
|
|
|
|
|
log_json["log"][i]["level"],
|
|
|
|
|
log_json["log"][i]["message"]
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
already_displayed.add(log_json["log"][i]["message"])
|
|
|
|
|
|
|
|
|
|
|
2017-10-24 06:22:21 +00:00
|
|
|
def find_sqlmap(to_find="sqlmap"):
|
2017-09-07 17:54:16 +00:00
|
|
|
"""
|
|
|
|
|
find sqlmap on the users system
|
|
|
|
|
"""
|
2017-10-24 06:22:21 +00:00
|
|
|
found_path = lib.core.settings.find_application(to_find)
|
2017-10-11 19:36:34 +00:00
|
|
|
return found_path
|
2017-09-07 17:54:16 +00:00
|
|
|
|
|
|
|
|
|
2017-11-11 16:43:50 +00:00
|
|
|
def sqlmap_scan_main(url, port=None, verbose=None, opts=None, auto_start=False):
|
2017-09-07 17:54:16 +00:00
|
|
|
"""
|
|
|
|
|
the main function that will be called and initialize everything
|
|
|
|
|
"""
|
|
|
|
|
|
2017-10-13 18:15:46 +00:00
|
|
|
is_started = lib.core.settings.search_for_process("sqlmapapi.py")
|
2017-10-24 06:22:21 +00:00
|
|
|
found_path = find_sqlmap()
|
2017-10-13 18:15:46 +00:00
|
|
|
|
2017-10-11 19:36:34 +00:00
|
|
|
if auto_start:
|
2017-10-25 18:26:20 +00:00
|
|
|
lib.core.settings.logger.info(lib.core.settings.set_color(
|
2017-10-24 06:22:21 +00:00
|
|
|
"attempting to launch sqlmap API..."
|
2017-09-07 17:54:16 +00:00
|
|
|
))
|
2017-10-25 21:32:27 +00:00
|
|
|
sqlmap_api_command = shlex.split("sudo sh {} p {}".format(
|
|
|
|
|
lib.core.settings.LAUNCH_SQLMAP_API_TOOL, "".join(found_path)
|
|
|
|
|
))
|
|
|
|
|
subprocess.Popen(sqlmap_api_command, stdout=subprocess.PIPE)
|
2017-10-25 18:26:20 +00:00
|
|
|
if is_started:
|
|
|
|
|
lib.core.settings.logger.info(lib.core.settings.set_color(
|
|
|
|
|
"sqlmap API is up and running, continuing process..."
|
|
|
|
|
))
|
|
|
|
|
else:
|
|
|
|
|
lib.core.settings.logger.error(lib.core.settings.set_color(
|
|
|
|
|
"there was a problem starting sqlmap API...", level=40
|
|
|
|
|
))
|
2017-11-20 20:27:08 +00:00
|
|
|
lib.core.common.prompt(
|
2017-10-25 18:26:20 +00:00
|
|
|
"manually start the API and press enter when ready..."
|
|
|
|
|
)
|
2017-10-11 19:36:34 +00:00
|
|
|
else:
|
|
|
|
|
if not is_started:
|
2017-11-20 20:27:08 +00:00
|
|
|
lib.core.common.prompt(
|
2017-10-11 19:36:34 +00:00
|
|
|
"sqlmap API is not started, start it and press enter to continue..."
|
|
|
|
|
)
|
|
|
|
|
try:
|
|
|
|
|
sqlmap_scan = SqlmapHook(url, port=port)
|
|
|
|
|
lib.core.settings.logger.info(lib.core.settings.set_color(
|
|
|
|
|
"initializing new sqlmap scan with given URL '{}'...".format(url)
|
|
|
|
|
))
|
|
|
|
|
sqlmap_scan.init_new_scan()
|
|
|
|
|
if verbose:
|
|
|
|
|
lib.core.settings.logger.debug(lib.core.settings.set_color(
|
|
|
|
|
"scan initialized...", level=10
|
2017-09-07 17:54:16 +00:00
|
|
|
))
|
2017-10-11 19:36:34 +00:00
|
|
|
lib.core.settings.logger.info(lib.core.settings.set_color(
|
|
|
|
|
"gathering sqlmap API scan ID..."
|
|
|
|
|
))
|
|
|
|
|
api_id = sqlmap_scan.get_scan_id()
|
|
|
|
|
if verbose:
|
|
|
|
|
lib.core.settings.logger.debug(lib.core.settings.set_color(
|
|
|
|
|
"current sqlmap scan ID: '{}'...".format(api_id), level=10
|
|
|
|
|
))
|
|
|
|
|
lib.core.settings.logger.info(lib.core.settings.set_color(
|
2017-11-09 02:01:12 +00:00
|
|
|
"starting sqlmap scan on url: '{}'...".format(url), level=25
|
2017-10-11 19:36:34 +00:00
|
|
|
))
|
|
|
|
|
if opts:
|
2017-09-07 17:54:16 +00:00
|
|
|
if verbose:
|
2017-10-10 22:01:13 +00:00
|
|
|
lib.core.settings.logger.debug(lib.core.settings.set_color(
|
2017-11-11 21:09:20 +00:00
|
|
|
"using arguments: '{}'...".format(opts), level=10
|
2017-09-07 17:54:16 +00:00
|
|
|
))
|
2017-10-10 22:01:13 +00:00
|
|
|
lib.core.settings.logger.info(lib.core.settings.set_color(
|
2017-10-11 19:36:34 +00:00
|
|
|
"adding arguments to sqlmap API..."
|
2017-09-07 17:54:16 +00:00
|
|
|
))
|
2017-10-11 19:36:34 +00:00
|
|
|
else:
|
|
|
|
|
if verbose:
|
|
|
|
|
lib.core.settings.logger.debug(lib.core.settings.set_color(
|
|
|
|
|
"no arguments passed, skipping...", level=10
|
2017-09-07 17:54:16 +00:00
|
|
|
))
|
2017-10-11 19:36:34 +00:00
|
|
|
lib.core.settings.logger.warning(lib.core.settings.set_color(
|
|
|
|
|
"please keep in mind that this is the API, output will "
|
|
|
|
|
"not be saved to log file, it may take a little longer "
|
|
|
|
|
"to finish processing, launching sqlmap...", level=30
|
|
|
|
|
))
|
|
|
|
|
sqlmap_scan.start_scan(api_id, opts=opts)
|
|
|
|
|
print("-" * 30)
|
|
|
|
|
sqlmap_scan.show_sqlmap_log(api_id)
|
|
|
|
|
print("-" * 30)
|
|
|
|
|
except requests.exceptions.HTTPError as e:
|
|
|
|
|
lib.core.settings.logger.exception(lib.core.settings.set_color(
|
|
|
|
|
"ran into error '{}', seems you didn't start the server, check "
|
|
|
|
|
"the server port and try again...".format(e), level=50
|
|
|
|
|
))
|
|
|
|
|
pass
|
2017-11-26 01:59:09 +00:00
|
|
|
except KeyboardInterrupt:
|
|
|
|
|
if not lib.core.common.pause():
|
|
|
|
|
lib.core.common.shutdown()
|
2017-10-11 19:36:34 +00:00
|
|
|
except Exception as e:
|
|
|
|
|
if "HTTPConnectionPool(host='127.0.0.1'" in str(e):
|
|
|
|
|
lib.core.settings.logger.error(lib.core.settings.set_color(
|
|
|
|
|
"sqlmap API is not started, did you forget to start it? "
|
|
|
|
|
"You will need to open a new terminal, cd into sqlmap, and "
|
|
|
|
|
"run `python sqlmapapi.py -s` otherwise pass the correct flags "
|
|
|
|
|
"to auto start the API...", level=40
|
2017-09-07 17:54:16 +00:00
|
|
|
))
|
2017-10-11 19:36:34 +00:00
|
|
|
pass
|
|
|
|
|
else:
|
2017-10-10 22:01:13 +00:00
|
|
|
lib.core.settings.logger.exception(lib.core.settings.set_color(
|
2017-10-11 19:36:34 +00:00
|
|
|
"ran into error '{}', seems something went wrong, error has "
|
|
|
|
|
"been saved to current log file.".format(e), level=50
|
2017-09-07 17:54:16 +00:00
|
|
|
))
|
2017-10-11 19:36:34 +00:00
|
|
|
request_issue_creation()
|
2017-09-07 17:54:16 +00:00
|
|
|
pass
|