mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2025-07-11 08:42:36 +03:00
increased SQLite connection timeout to 3 seconds, the object will now wait for the lock to go away max 3 seconds, no longer 1 only. Relevant code refactoring and minor improvements all over the API library (issue #297)
This commit is contained in:
parent
9677e0f910
commit
1152cf8958
120
lib/utils/api.py
120
lib/utils/api.py
|
@ -60,10 +60,10 @@ class Database(object):
|
||||||
|
|
||||||
def create(self):
|
def create(self):
|
||||||
_, self.database = tempfile.mkstemp(prefix="sqlmapipc-", text=False)
|
_, self.database = tempfile.mkstemp(prefix="sqlmapipc-", text=False)
|
||||||
logger.info("IPC database is %s" % self.database)
|
logger.debug("IPC database: %s" % self.database)
|
||||||
|
|
||||||
def connect(self):
|
def connect(self):
|
||||||
self.connection = sqlite3.connect(self.database, timeout=1, isolation_level=None)
|
self.connection = sqlite3.connect(self.database, timeout=3, isolation_level=None)
|
||||||
self.cursor = self.connection.cursor()
|
self.cursor = self.connection.cursor()
|
||||||
|
|
||||||
def disconnect(self):
|
def disconnect(self):
|
||||||
|
@ -132,18 +132,28 @@ class Task(object):
|
||||||
shutil.rmtree(self.output_directory)
|
shutil.rmtree(self.output_directory)
|
||||||
|
|
||||||
def engine_start(self):
|
def engine_start(self):
|
||||||
self.process = Popen("python sqlmap.py --pickled-options %s" % base64pickle(self.options), shell=True, stdin=PIPE)
|
self.process = Popen("python sqlmap.py --pickled-options %s" % base64pickle(self.options), shell=True, stdin=PIPE, close_fds=False)
|
||||||
|
|
||||||
def engine_stop(self):
|
def engine_stop(self):
|
||||||
if self.process:
|
if self.process:
|
||||||
self.process.terminate()
|
return self.process.terminate()
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
def engine_kill(self):
|
def engine_kill(self):
|
||||||
if self.process:
|
if self.process:
|
||||||
self.process.kill()
|
return self.process.kill()
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
def engine_get_pid(self):
|
def engine_get_id(self):
|
||||||
return self.processid.pid
|
if self.process:
|
||||||
|
return self.process.pid
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def engine_has_terminated(self):
|
||||||
|
return isinstance(self.process.returncode, int) == True
|
||||||
|
|
||||||
# Wrapper functions for sqlmap engine
|
# Wrapper functions for sqlmap engine
|
||||||
class StdDbOut(object):
|
class StdDbOut(object):
|
||||||
|
@ -162,9 +172,13 @@ class StdDbOut(object):
|
||||||
|
|
||||||
def write(self, value, status=None, content_type=None):
|
def write(self, value, status=None, content_type=None):
|
||||||
if self.messagetype == "stdout":
|
if self.messagetype == "stdout":
|
||||||
conf.database_cursor.execute("INSERT INTO data VALUES(NULL, ?, ?, ?, ?)", (self.taskid, status, content_type, jsonize(value)))
|
#conf.database_cursor.execute("INSERT INTO data VALUES(NULL, ?, ?, ?, ?)",
|
||||||
|
# (self.taskid, status, content_type, base64pickle(value)))
|
||||||
|
conf.database_cursor.execute("INSERT INTO data VALUES(NULL, ?, ?, ?, ?)",
|
||||||
|
(self.taskid, status, content_type, jsonize(value)))
|
||||||
else:
|
else:
|
||||||
conf.database_cursor.execute("INSERT INTO errors VALUES(NULL, ?, ?)", (self.taskid, value))
|
conf.database_cursor.execute("INSERT INTO errors VALUES(NULL, ?, ?)",
|
||||||
|
(self.taskid, str(value) if value else ""))
|
||||||
|
|
||||||
def flush(self):
|
def flush(self):
|
||||||
pass
|
pass
|
||||||
|
@ -182,8 +196,7 @@ class LogRecorder(logging.StreamHandler):
|
||||||
communication with the parent process
|
communication with the parent process
|
||||||
"""
|
"""
|
||||||
conf.database_cursor.execute("INSERT INTO logs VALUES(NULL, ?, ?, ?, ?)",
|
conf.database_cursor.execute("INSERT INTO logs VALUES(NULL, ?, ?, ?, ?)",
|
||||||
(conf.taskid, time.strftime("%X"), record.levelname,
|
(conf.taskid, time.strftime("%X"), record.levelname, record.msg % record.args if record.args else record.msg))
|
||||||
record.msg % record.args if record.args else record.msg))
|
|
||||||
|
|
||||||
def setRestAPILog():
|
def setRestAPILog():
|
||||||
if hasattr(conf, "api"):
|
if hasattr(conf, "api"):
|
||||||
|
@ -257,35 +270,44 @@ def task_new():
|
||||||
taskid = hexencode(os.urandom(8))
|
taskid = hexencode(os.urandom(8))
|
||||||
tasks[taskid] = Task(taskid)
|
tasks[taskid] = Task(taskid)
|
||||||
|
|
||||||
|
logger.debug("Created new task ID: %s" % taskid)
|
||||||
|
|
||||||
return jsonize({"taskid": taskid})
|
return jsonize({"taskid": taskid})
|
||||||
|
|
||||||
@get("/task/<taskid>/destroy")
|
@get("/task/<taskid>/delete")
|
||||||
def task_destroy(taskid):
|
def task_delete(taskid):
|
||||||
"""
|
"""
|
||||||
Destroy own task ID
|
Delete own task ID
|
||||||
"""
|
"""
|
||||||
if taskid in tasks:
|
if taskid in tasks:
|
||||||
tasks[taskid].clean_filesystem()
|
tasks[taskid].clean_filesystem()
|
||||||
tasks.pop(taskid)
|
tasks.pop(taskid)
|
||||||
|
|
||||||
|
logger.debug("Deleted task ID: %s" % taskid)
|
||||||
|
|
||||||
return jsonize({"success": True})
|
return jsonize({"success": True})
|
||||||
else:
|
else:
|
||||||
abort(500, "Invalid task ID")
|
abort(500, "Invalid task ID")
|
||||||
|
|
||||||
# Admin's methods
|
###################
|
||||||
@get("/task/<taskid>/list")
|
# Admin functions #
|
||||||
|
###################
|
||||||
|
|
||||||
|
@get("/admin/<taskid>/list")
|
||||||
def task_list(taskid):
|
def task_list(taskid):
|
||||||
"""
|
"""
|
||||||
List all active tasks
|
List task poll
|
||||||
"""
|
"""
|
||||||
if is_admin(taskid):
|
if is_admin(taskid):
|
||||||
return jsonize({"tasks": tasks})
|
logger.debug("Listed task poll")
|
||||||
|
return jsonize({"tasks": tasks, "tasks_num": len(tasks)})
|
||||||
else:
|
else:
|
||||||
abort(401)
|
abort(401)
|
||||||
|
|
||||||
@get("/task/<taskid>/flush")
|
@get("/admin/<taskid>/flush")
|
||||||
def task_flush(taskid):
|
def task_flush(taskid):
|
||||||
"""
|
"""
|
||||||
Flush task spool (destroy all tasks)
|
Flush task spool (delete all tasks)
|
||||||
"""
|
"""
|
||||||
global tasks
|
global tasks
|
||||||
|
|
||||||
|
@ -294,6 +316,7 @@ def task_flush(taskid):
|
||||||
tasks[task].clean_filesystem()
|
tasks[task].clean_filesystem()
|
||||||
|
|
||||||
tasks = dict()
|
tasks = dict()
|
||||||
|
logger.debug("Flushed task poll")
|
||||||
return jsonize({"success": True})
|
return jsonize({"success": True})
|
||||||
else:
|
else:
|
||||||
abort(401)
|
abort(401)
|
||||||
|
@ -302,20 +325,7 @@ def task_flush(taskid):
|
||||||
# sqlmap core interact functions #
|
# sqlmap core interact functions #
|
||||||
##################################
|
##################################
|
||||||
|
|
||||||
# Admin's methods
|
# Handle task's options
|
||||||
@get("/status/<taskid>")
|
|
||||||
def status(taskid):
|
|
||||||
"""
|
|
||||||
Verify the status of the API as well as the core
|
|
||||||
"""
|
|
||||||
|
|
||||||
if is_admin(taskid):
|
|
||||||
tasks_num = len(tasks)
|
|
||||||
return jsonize({"tasks": tasks_num})
|
|
||||||
else:
|
|
||||||
abort(401)
|
|
||||||
|
|
||||||
# Functions to handle options
|
|
||||||
@get("/option/<taskid>/list")
|
@get("/option/<taskid>/list")
|
||||||
def option_list(taskid):
|
def option_list(taskid):
|
||||||
"""
|
"""
|
||||||
|
@ -324,7 +334,7 @@ def option_list(taskid):
|
||||||
if taskid not in tasks:
|
if taskid not in tasks:
|
||||||
abort(500, "Invalid task ID")
|
abort(500, "Invalid task ID")
|
||||||
|
|
||||||
return jsonize(tasks[taskid].get_options())
|
return jsonize({"options": tasks[taskid].get_options()})
|
||||||
|
|
||||||
@post("/option/<taskid>/get")
|
@post("/option/<taskid>/get")
|
||||||
def option_get(taskid):
|
def option_get(taskid):
|
||||||
|
@ -339,7 +349,7 @@ def option_get(taskid):
|
||||||
if option in tasks[taskid]:
|
if option in tasks[taskid]:
|
||||||
return jsonize({option: tasks[taskid].get_option(option)})
|
return jsonize({option: tasks[taskid].get_option(option)})
|
||||||
else:
|
else:
|
||||||
return jsonize({option: None})
|
return jsonize({option: "Not set"})
|
||||||
|
|
||||||
@post("/option/<taskid>/set")
|
@post("/option/<taskid>/set")
|
||||||
def option_set(taskid):
|
def option_set(taskid):
|
||||||
|
@ -356,7 +366,7 @@ def option_set(taskid):
|
||||||
|
|
||||||
return jsonize({"success": True})
|
return jsonize({"success": True})
|
||||||
|
|
||||||
# Function to handle scans
|
# Handle scans
|
||||||
@post("/scan/<taskid>/start")
|
@post("/scan/<taskid>/start")
|
||||||
def scan_start(taskid):
|
def scan_start(taskid):
|
||||||
"""
|
"""
|
||||||
|
@ -375,12 +385,12 @@ def scan_start(taskid):
|
||||||
tasks[taskid].set_output_directory()
|
tasks[taskid].set_output_directory()
|
||||||
|
|
||||||
# Launch sqlmap engine in a separate thread
|
# Launch sqlmap engine in a separate thread
|
||||||
logger.debug("starting a scan for task ID %s" % taskid)
|
logger.debug("Starting a scan for task ID %s" % taskid)
|
||||||
|
|
||||||
# Launch sqlmap engine
|
# Launch sqlmap engine
|
||||||
tasks[taskid].engine_start()
|
tasks[taskid].engine_start()
|
||||||
|
|
||||||
return jsonize({"success": True})
|
return jsonize({"success": True, "engineid": tasks[taskid].engine_get_id()})
|
||||||
|
|
||||||
@get("/scan/<taskid>/stop")
|
@get("/scan/<taskid>/stop")
|
||||||
def scan_stop(taskid):
|
def scan_stop(taskid):
|
||||||
|
@ -406,21 +416,6 @@ def scan_kill(taskid):
|
||||||
|
|
||||||
return jsonize({"success": tasks[taskid].engine_kill()})
|
return jsonize({"success": tasks[taskid].engine_kill()})
|
||||||
|
|
||||||
@get("/scan/<taskid>/delete")
|
|
||||||
def scan_delete(taskid):
|
|
||||||
"""
|
|
||||||
Delete a scan and corresponding temporary output directory and IPC database
|
|
||||||
"""
|
|
||||||
global tasks
|
|
||||||
|
|
||||||
if taskid not in tasks:
|
|
||||||
abort(500, "Invalid task ID")
|
|
||||||
|
|
||||||
scan_stop(taskid)
|
|
||||||
tasks[taskid].clean_filesystem()
|
|
||||||
|
|
||||||
return jsonize({"success": True})
|
|
||||||
|
|
||||||
@get("/scan/<taskid>/data")
|
@get("/scan/<taskid>/data")
|
||||||
def scan_data(taskid):
|
def scan_data(taskid):
|
||||||
"""
|
"""
|
||||||
|
@ -436,7 +431,8 @@ def scan_data(taskid):
|
||||||
|
|
||||||
# Read all data from the IPC database for the taskid
|
# Read all data from the IPC database for the taskid
|
||||||
for status, content_type, value in db.execute("SELECT status, content_type, value FROM data WHERE taskid = ? ORDER BY id ASC", (taskid,)):
|
for status, content_type, value in db.execute("SELECT status, content_type, value FROM data WHERE taskid = ? ORDER BY id ASC", (taskid,)):
|
||||||
json_data_message.append([status, content_type, dejsonize(value)])
|
#json_data_message.append({"status": status, "type": content_type, "value": base64unpickle(value)})
|
||||||
|
json_data_message.append({"status": status, "type": content_type, "value": dejsonize(value)})
|
||||||
|
|
||||||
# Read all error messages from the IPC database
|
# Read all error messages from the IPC database
|
||||||
for error in db.execute("SELECT error FROM errors WHERE taskid = ? ORDER BY id ASC", (taskid,)):
|
for error in db.execute("SELECT error FROM errors WHERE taskid = ? ORDER BY id ASC", (taskid,)):
|
||||||
|
@ -515,24 +511,26 @@ def server(host="0.0.0.0", port=RESTAPI_SERVER_PORT):
|
||||||
global db
|
global db
|
||||||
|
|
||||||
adminid = hexencode(os.urandom(16))
|
adminid = hexencode(os.urandom(16))
|
||||||
|
|
||||||
|
logger.info("Running REST-JSON API server at '%s:%d'.." % (host, port))
|
||||||
|
logger.info("Admin ID: %s" % adminid)
|
||||||
|
|
||||||
|
# Initialize IPC database
|
||||||
db = Database()
|
db = Database()
|
||||||
db.initialize()
|
db.initialize()
|
||||||
|
|
||||||
logger.info("running REST-JSON API server at '%s:%d'.." % (host, port))
|
|
||||||
logger.info("the admin task ID is: %s" % adminid)
|
|
||||||
|
|
||||||
# Run RESTful API
|
# Run RESTful API
|
||||||
run(host=host, port=port, quiet=False, debug=False)
|
run(host=host, port=port, quiet=True, debug=False)
|
||||||
|
|
||||||
def client(host=RESTAPI_SERVER_HOST, port=RESTAPI_SERVER_PORT):
|
def client(host=RESTAPI_SERVER_HOST, port=RESTAPI_SERVER_PORT):
|
||||||
"""
|
"""
|
||||||
REST-JSON API client
|
REST-JSON API client
|
||||||
"""
|
"""
|
||||||
addr = "http://%s:%d" % (host, port)
|
addr = "http://%s:%d" % (host, port)
|
||||||
logger.info("starting debug REST-JSON client to '%s'..." % addr)
|
logger.info("Starting REST-JSON API client to '%s'..." % addr)
|
||||||
|
|
||||||
# TODO: write a simple client with requests, for now use curl from command line
|
# TODO: write a simple client with requests, for now use curl from command line
|
||||||
logger.error("not yet implemented, use curl from command line instead for now, for example:")
|
logger.error("Not yet implemented, use curl from command line instead for now, for example:")
|
||||||
print "\n\t$ curl http://%s:%d/task/new" % (host, port)
|
print "\n\t$ curl http://%s:%d/task/new" % (host, port)
|
||||||
print "\t$ curl -H \"Content-Type: application/json\" -X POST -d '{\"url\": \"http://testphp.vulnweb.com/artists.php?artist=1\"}' http://%s:%d/scan/:taskid/start" % (host, port)
|
print "\t$ curl -H \"Content-Type: application/json\" -X POST -d '{\"url\": \"http://testphp.vulnweb.com/artists.php?artist=1\"}' http://%s:%d/scan/:taskid/start" % (host, port)
|
||||||
print "\t$ curl http://%s:%d/scan/:taskid/output" % (host, port)
|
print "\t$ curl http://%s:%d/scan/:taskid/output" % (host, port)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user