From 2895e5c20f6585da905e345e657c362ea0baec39 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 15 Nov 2018 15:27:05 +0100 Subject: [PATCH] Initial commit for #3140 --- lib/core/settings.py | 2 +- lib/utils/api.py | 43 +++++----- swagger.yaml | 188 +++++++++++++++++++++++++++++++++++++++++++ txt/checksum.md5 | 4 +- 4 files changed, 214 insertions(+), 23 deletions(-) create mode 100644 swagger.yaml diff --git a/lib/core/settings.py b/lib/core/settings.py index 9084bfef2..f40b36872 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -19,7 +19,7 @@ from lib.core.enums import DBMS_DIRECTORY_NAME from lib.core.enums import OS # sqlmap version (...) -VERSION = "1.2.11.7" +VERSION = "1.2.11.8" TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable" TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34} VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE) diff --git a/lib/utils/api.py b/lib/utils/api.py index 4d6316eed..7a7229ca5 100644 --- a/lib/utils/api.py +++ b/lib/utils/api.py @@ -58,7 +58,7 @@ from thirdparty.bottle.bottle import server_names # Global data storage class DataStore(object): - admin_id = "" + admin_token = "" current_db = None tasks = dict() username = None @@ -275,8 +275,8 @@ def setRestAPILog(): logger.addHandler(LOGGER_RECORDER) # Generic functions -def is_admin(taskid): - return DataStore.admin_id == taskid +def is_admin(token): + return DataStore.admin_token == token @hook('before_request') def check_authentication(): @@ -358,7 +358,7 @@ def path_401(): @get("/task/new") def task_new(): """ - Create new task ID + Create a new task """ taskid = hexencode(os.urandom(8)) remote_addr = request.remote_addr @@ -371,7 +371,7 @@ def task_new(): @get("/task//delete") def task_delete(taskid): """ - Delete own task ID + Delete an existing task """ if taskid in DataStore.tasks: DataStore.tasks.pop(taskid) @@ -379,39 +379,42 @@ def task_delete(taskid): logger.debug("[%s] Deleted task" % taskid) return jsonize({"success": True}) else: - logger.warning("[%s] Invalid task ID provided to task_delete()" % taskid) - return jsonize({"success": False, "message": "Invalid task ID"}) + response.status = 404 + logger.warning("[%s] Non-existing task ID provided to task_delete()" % taskid) + return jsonize({"success": False, "message": "Non-existing task ID"}) ################### # Admin functions # ################### -@get("/admin//list") -def task_list(taskid=None): +@get("/admin/list") +@get("/admin//list") +def task_list(token=None): """ - List task pull + Pull task list """ tasks = {} for key in DataStore.tasks: - if is_admin(taskid) or DataStore.tasks[key].remote_addr == request.remote_addr: + if is_admin(token) or DataStore.tasks[key].remote_addr == request.remote_addr: tasks[key] = dejsonize(scan_status(key))["status"] - logger.debug("[%s] Listed task pool (%s)" % (taskid, "admin" if is_admin(taskid) else request.remote_addr)) + logger.debug("[%s] Listed task pool (%s)" % (token, "admin" if is_admin(token) else request.remote_addr)) return jsonize({"success": True, "tasks": tasks, "tasks_num": len(tasks)}) -@get("/admin//flush") -def task_flush(taskid): +@get("/admin/flush") +@get("/admin//flush") +def task_flush(token=None): """ Flush task spool (delete all tasks) """ for key in list(DataStore.tasks): - if is_admin(taskid) or DataStore.tasks[key].remote_addr == request.remote_addr: + if is_admin(token) or DataStore.tasks[key].remote_addr == request.remote_addr: DataStore.tasks[key].engine_kill() del DataStore.tasks[key] - logger.debug("[%s] Flushed task pool (%s)" % (taskid, "admin" if is_admin(taskid) else request.remote_addr)) + logger.debug("[%s] Flushed task pool (%s)" % (token, "admin" if is_admin(token) else request.remote_addr)) return jsonize({"success": True}) ################################## @@ -647,7 +650,7 @@ def server(host=RESTAPI_DEFAULT_ADDRESS, port=RESTAPI_DEFAULT_PORT, adapter=REST REST-JSON API server """ - DataStore.admin_id = hexencode(os.urandom(16)) + DataStore.admin_token = hexencode(os.urandom(16)) DataStore.username = username DataStore.password = password @@ -660,7 +663,7 @@ def server(host=RESTAPI_DEFAULT_ADDRESS, port=RESTAPI_DEFAULT_PORT, adapter=REST port = s.getsockname()[1] logger.info("Running REST-JSON API server at '%s:%d'.." % (host, port)) - logger.info("Admin ID: %s" % DataStore.admin_id) + logger.info("Admin (secret) token: %s" % DataStore.admin_token) logger.debug("IPC database: '%s'" % Database.filepath) # Initialize IPC database @@ -696,7 +699,7 @@ def server(host=RESTAPI_DEFAULT_ADDRESS, port=RESTAPI_DEFAULT_PORT, adapter=REST logger.critical(errMsg) def _client(url, options=None): - logger.debug("Calling %s" % url) + logger.debug("Calling '%s'" % url) try: data = None if options is not None: @@ -833,7 +836,7 @@ def client(host=RESTAPI_DEFAULT_ADDRESS, port=RESTAPI_DEFAULT_PORT, username=Non logger.info("Switching to task ID '%s' " % taskid) elif command in ("list", "flush"): - raw = _client("%s/admin/%s/%s" % (addr, taskid or 0, command)) + raw = _client("%s/admin/%s" % (addr, command)) res = dejsonize(raw) if not res["success"]: logger.error("Failed to execute command %s" % command) diff --git a/swagger.yaml b/swagger.yaml new file mode 100644 index 000000000..3f00bf4d8 --- /dev/null +++ b/swagger.yaml @@ -0,0 +1,188 @@ +swagger: "2.0" +info: + description: "" + version: "1.2" + title: "sqlmap API (REST-JSON)" + contact: + email: "dev@sqlmap.org" + license: + name: "GPL 2.0" + url: "https://www.gnu.org/licenses/old-licenses/gpl-2.0.html" +host: "0.0.0.0:8775" +basePath: "/" +tags: +- name: "task" + description: "Task management functions" +- name: "admin" + description: "Task administration functions" +- name: "option" + description: "Task option handling functions" +schemes: +- "http" +paths: + /task/new: + get: + tags: + - "task" + summary: "Create a new task" + description: "" + operationId: "taskNew" + produces: + - "application/json" + parameters: [] + responses: + 200: + description: "Task successfully created" + schema: + type: object + properties: + success: + type: boolean + taskid: + type: string + example: "7e605b5d5a892b74" + /task/{taskid}/delete: + get: + tags: + - "task" + summary: "Delete an existing task" + description: "" + operationId: "taskDelete" + produces: + - "application/json" + parameters: + - name: "taskid" + in: "path" + description: "ID of an existing task to delete" + required: true + type: "string" + responses: + 200: + description: "Task successfully deleted" + schema: + type: object + properties: + success: + type: boolean + enum: [true] + 404: + description: "Task ID not found" + schema: + type: object + properties: + success: + type: boolean + enum: [false] + message: + type: string + enum: ["Non-existing task ID"] + /admin/list: + get: + tags: + - "admin" + summary: "Pull task list (locally)" + description: "Note: Use in cases when connecting to server from same IP (e.g. `localhost`)" + operationId: "adminList" + produces: + - "application/json" + responses: + 200: + description: "Task list successfully pulled" + schema: + type: object + properties: + success: + type: boolean + enum: [true] + tasks: + type: object + additionalProperties: + type: string + example: + 16a7a898e8eaaf45: running + 644fc063408e4f12: not running + 8e2eb10770d913cd: not running + d59d1c69bdc06933: not running + tasks_num: + type: integer + example: 4 + /admin/{token}/list: + get: + tags: + - "admin" + summary: "Pull task list (remotely)" + description: "Note: Use in cases when connecting to server from different IP" + operationId: "adminListToken" + produces: + - "application/json" + parameters: + - name: "token" + in: "path" + description: "Secret token (Note: written to console during a server run - e.g. `2756d5b6e7d093ba49b5fd06a93aca7a`)" + required: true + type: "string" + responses: + 200: + description: "Task list successfully pulled" + schema: + type: object + properties: + success: + type: boolean + enum: [true] + tasks: + type: object + additionalProperties: + type: string + example: + 5c911efa476b55f4: not running + 5ee038e153ffc534: not running + e58c7a4de6bf7f51: not running + tasks_num: + type: integer + example: 4 + /admin/flush: + get: + tags: + - "admin" + summary: "Flush task pool (locally)" + description: "Note: Use in cases when connecting to server from same IP (e.g. `localhost`)" + operationId: "adminFlush" + produces: + - "application/json" + responses: + 200: + description: "Task pool successfully flushed" + schema: + type: object + properties: + success: + type: boolean + enum: [true] + /admin/{token}/flush: + get: + tags: + - "admin" + summary: "Flush task pool (remotely)" + description: "Note: Use in cases when connecting to server from different IP" + operationId: "adminFlushToken" + produces: + - "application/json" + parameters: + - name: "token" + in: "path" + description: "Secret token (Note: written to console during a server run - e.g. `2756d5b6e7d093ba49b5fd06a93aca7a`)" + required: true + type: "string" + responses: + 200: + description: "Task pool successfully flushed" + schema: + type: object + properties: + success: + type: boolean + enum: [true] +externalDocs: + description: "Find out more about sqlmap API (REST-JSON)" + url: "https://github.com/sqlmapproject/sqlmap/wiki/Usage#api-rest-json" \ No newline at end of file diff --git a/txt/checksum.md5 b/txt/checksum.md5 index b0fee5497..3ee88a07c 100644 --- a/txt/checksum.md5 +++ b/txt/checksum.md5 @@ -49,7 +49,7 @@ c8c386d644d57c659d74542f5f57f632 lib/core/patch.py 0c3eef46bdbf87e29a3f95f90240d192 lib/core/replication.py a7db43859b61569b601b97f187dd31c5 lib/core/revision.py fcb74fcc9577523524659ec49e2e964b lib/core/session.py -2ec7d2bc8a0e0c387488c41c0cd44f51 lib/core/settings.py +f6c316b9de14838f5a70072e514c5974 lib/core/settings.py a971ce157d04de96ba6e710d3d38a9a8 lib/core/shell.py a7edc9250d13af36ac0108f259859c19 lib/core/subprocessng.py 721198b5be72c8015a02acb116532a1f lib/core/target.py @@ -101,7 +101,7 @@ db208ab47de010836c6bf044e2357861 lib/techniques/blind/inference.py 1e5532ede194ac9c083891c2f02bca93 lib/techniques/union/__init__.py f7813cdee00df8f98d6f811475e520a1 lib/techniques/union/test.py 7361338240ecd9d01d1d10ec76bce069 lib/techniques/union/use.py -77ff35587af9e3dfde63b8327e230f9a lib/utils/api.py +dfea8e2ca23c5160b2f57732d8d49023 lib/utils/api.py 37dfb641358669f62c2acedff241348b lib/utils/brute.py 31b1e7eb489eac837db6a2bc1dcb7da7 lib/utils/crawler.py f9867bbfcd6d31916ca73e72e95fd881 lib/utils/deps.py