mirror of
				https://github.com/sqlmapproject/sqlmap.git
				synced 2025-10-31 16:07:55 +03:00 
			
		
		
		
	refactoring, code cleanup, more security-related headers and first /scan method implementation (issue #297)
This commit is contained in:
		
							parent
							
								
									a2a71bb37b
								
							
						
					
					
						commit
						0b71c85d95
					
				|  | @ -8,6 +8,7 @@ See the file 'doc/COPYING' for copying permission | ||||||
| import argparse | import argparse | ||||||
| import os | import os | ||||||
| import sys | import sys | ||||||
|  | import threading | ||||||
| 
 | 
 | ||||||
| try: | try: | ||||||
|     import simplejson as json |     import simplejson as json | ||||||
|  | @ -39,135 +40,160 @@ from lib.core.option import init | ||||||
| from lib.core.settings import UNICODE_ENCODING | from lib.core.settings import UNICODE_ENCODING | ||||||
| from lib.core.settings import RESTAPI_SERVER_PORT | from lib.core.settings import RESTAPI_SERVER_PORT | ||||||
| 
 | 
 | ||||||
| 
 | # Local global variables | ||||||
| # local global variables | options = AttribDict() | ||||||
| session_ids = [] | adminid = "" | ||||||
| admin_id = "" | tasks = [] | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| # Generic functions | # Generic functions | ||||||
| def jsonize(data): | def jsonize(data): | ||||||
|     #return json.dumps(data, sort_keys=False, indent=4) |  | ||||||
|     return json.dumps(data, sort_keys=False) |     return json.dumps(data, sort_keys=False) | ||||||
| 
 | 
 | ||||||
| 
 | def is_admin(taskid): | ||||||
| def is_admin(session_id): |     global adminid | ||||||
|     global admin_id |     #print "[INFO] Admin ID:   %s" % adminid | ||||||
|     #print "[INFO] Admin ID:   %s" % admin_id |     #print "[INFO] Task ID: %s" % taskid | ||||||
|     #print "[INFO] Session ID: %s" % session_id |     if adminid != taskid: | ||||||
|     if admin_id != session_id: |  | ||||||
|         return False |         return False | ||||||
|     else: |     else: | ||||||
|         return True |         return True | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| @hook('after_request') | @hook('after_request') | ||||||
| def security_headers(): | def security_headers(): | ||||||
|     """ |     """ | ||||||
|     Set some headers across all HTTP responses |     Set some headers across all HTTP responses | ||||||
|     """ |     """ | ||||||
|     response.headers["Server"] = "Server" |     response.headers["Server"] = "Server" | ||||||
|     response.headers["X-Frame-Options"] = "sameorigin" |     response.headers["X-Content-Type-Options"] = "nosniff" | ||||||
|  |     response.headers["X-Frame-Options"] = "DENY" | ||||||
|     response.headers["X-XSS-Protection"] = "1; mode=block" |     response.headers["X-XSS-Protection"] = "1; mode=block" | ||||||
|  |     response.headers["Pragma"] = "no-cache" | ||||||
|  |     response.headers["Cache-Control"] = "no-cache" | ||||||
|  |     response.headers["Expires"] = "0" | ||||||
|  |     response.content_type = "application/json; charset=UTF-8" | ||||||
| 
 | 
 | ||||||
|  | ############################## | ||||||
|  | # HTTP Status Code functions # | ||||||
|  | ############################## | ||||||
| 
 | 
 | ||||||
| # HTTP Status Code functions |  | ||||||
| @error(401) # Access Denied | @error(401) # Access Denied | ||||||
| def error401(error): | def error401(error=None): | ||||||
|     return "Access denied" |     return "Access denied" | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| @error(404) # Not Found | @error(404) # Not Found | ||||||
| def error404(error): | def error404(error=None): | ||||||
|     return "Nothing here" |     return "Nothing here" | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| @error(405) # Method Not Allowed (e.g. when requesting a POST method via GET) | @error(405) # Method Not Allowed (e.g. when requesting a POST method via GET) | ||||||
| def error405(error): | def error405(error=None): | ||||||
|     return "Method not allowed" |     return "Method not allowed" | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| @error(500) # Internal Server Error | @error(500) # Internal Server Error | ||||||
| def error500(error): | def error500(error=None): | ||||||
|     return "Internal server error" |     return "Internal server error" | ||||||
| 
 | 
 | ||||||
| 
 | ############################# | ||||||
| ################################ | # Task management functions # | ||||||
| # Session management functions # | ############################# | ||||||
| ################################ |  | ||||||
| 
 | 
 | ||||||
| # Users' methods | # Users' methods | ||||||
| @get("/session/new") | @get("/task/new") | ||||||
| def session_new(): | def task_new(): | ||||||
|     """ |     """ | ||||||
|     Create new session token |     Create new task ID | ||||||
|     """ |     """ | ||||||
|     global session_ids |     global tasks | ||||||
|     session_id = hexencode(os.urandom(32)) |     taskid = hexencode(os.urandom(32)) | ||||||
|     session_ids.append(session_id) |     tasks.append(taskid) | ||||||
|     response.content_type = "application/json; charset=UTF-8" |     return jsonize({"taskid": taskid}) | ||||||
|     return jsonize({"sessionid": session_id}) |  | ||||||
| 
 | 
 | ||||||
| 
 | @get("/task/<taskid>/destroy") | ||||||
| @post("/session/destroy") | def task_destroy(taskid): | ||||||
| def session_destroy(): |  | ||||||
|     """ |     """ | ||||||
|     Destroy own session token |     Destroy own task ID | ||||||
|     """ |     """ | ||||||
|     session_id = request.json.get("sessionid", "") |     if taskid in tasks: | ||||||
|     if session_id in session_ids: |         tasks.remove(taskid) | ||||||
|         session_ids.remove(session_id) |  | ||||||
|         return jsonize({"success": True}) |         return jsonize({"success": True}) | ||||||
|     else: |     else: | ||||||
|         abort(500) |         abort(500, "Invalid task ID") | ||||||
| 
 | 
 | ||||||
| # Admin's methods | # Admin's methods | ||||||
| @post("/session/list") | @get("/task/<taskid>/list") | ||||||
| def session_list(): | def task_list(taskid): | ||||||
|     """ |     """ | ||||||
|     List all active sessions |     List all active tasks | ||||||
|     """ |     """ | ||||||
|     if is_admin(request.json.get("sessionid", "")): |     if is_admin(taskid): | ||||||
|         response.content_type = "application/json; charset=UTF-8" |         return jsonize({"tasks": tasks}) | ||||||
|         return jsonize({"sessions": session_ids}) |  | ||||||
|     else: |     else: | ||||||
|         abort(401) |         abort(401) | ||||||
| 
 | 
 | ||||||
| 
 | @get("/task/<taskid>/flush") | ||||||
| @post("/session/flush") | def task_flush(taskid): | ||||||
| def session_flush(): |  | ||||||
|     """ |     """ | ||||||
|     Flush session spool (destroy all sessions) |     Flush task spool (destroy all tasks) | ||||||
|     """ |     """ | ||||||
|     global session_ids |     global tasks | ||||||
|     if is_admin(request.json.get("sessionid", "")): |     if is_admin(taskid): | ||||||
|         session_ids = [] |         tasks = [] | ||||||
|         return jsonize({"success": True}) |         return jsonize({"success": True}) | ||||||
|     else: |     else: | ||||||
|         abort(401) |         abort(401) | ||||||
| 
 | 
 | ||||||
|  | ################################## | ||||||
|  | # sqlmap core interact functions # | ||||||
|  | ################################## | ||||||
|  | @post("/scan/<taskid>") | ||||||
|  | def scan(taskid): | ||||||
|  |     """ | ||||||
|  |     Mount a scan with sqlmap | ||||||
|  |     """ | ||||||
|  |     global options | ||||||
| 
 | 
 | ||||||
| @post("/download/<target>/<filename:path>") |     if taskid not in tasks: | ||||||
| def download(target, filename): |         abort(500, "Invalid task ID") | ||||||
|  | 
 | ||||||
|  |     # Initialize sqlmap engine's options with user's provided options | ||||||
|  |     # within the JSON request | ||||||
|  |     for key, value in request.json.items(): | ||||||
|  |         if key != "taskid": | ||||||
|  |             options[key] = value | ||||||
|  |     init(options, True) | ||||||
|  | 
 | ||||||
|  |     # Launch sqlmap engine in a separate thread | ||||||
|  |     thread = threading.Thread(target=start) | ||||||
|  |     thread.daemon = True | ||||||
|  |     thread.start() | ||||||
|  | 
 | ||||||
|  |     return jsonize({"success": True}) | ||||||
|  | 
 | ||||||
|  | @post("/download/<taskid>/<target>/<filename:path>") | ||||||
|  | def download(taskid, target, filename): | ||||||
|     """ |     """ | ||||||
|     Download a certain file from the file system |     Download a certain file from the file system | ||||||
|     """ |     """ | ||||||
|  |     if taskid not in tasks: | ||||||
|  |         abort(500, "Invalid task ID") | ||||||
|  | 
 | ||||||
|     path = os.path.join(paths.SQLMAP_OUTPUT_PATH, target) |     path = os.path.join(paths.SQLMAP_OUTPUT_PATH, target) | ||||||
|     if os.path.exists(path): |     if os.path.exists(path): | ||||||
|         return static_file(filename, root=path) |         return static_file(filename, root=path) | ||||||
|     else: |     else: | ||||||
|         abort(500) |         abort(500) | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| def restAPIrun(host="0.0.0.0", port=RESTAPI_SERVER_PORT): | def restAPIrun(host="0.0.0.0", port=RESTAPI_SERVER_PORT): | ||||||
|     """ |     """ | ||||||
|     Initiate REST-JSON API |     Initiate REST-JSON API | ||||||
|     """ |     """ | ||||||
|     global admin_id |     global adminid | ||||||
|     admin_id = hexencode(os.urandom(32)) |     global options | ||||||
|  |     global tasks | ||||||
|  |     adminid = hexencode(os.urandom(32)) | ||||||
|  |     tasks.append(adminid) | ||||||
|     options = AttribDict(cmdLineOptions) |     options = AttribDict(cmdLineOptions) | ||||||
|     logger.info("Running REST-JSON API server at '%s:%d'.." % (host, port)) |     logger.info("Running REST-JSON API server at '%s:%d'.." % (host, port)) | ||||||
|     logger.info("The admin session ID is: %s" % admin_id) |     logger.info("The admin task ID is: %s" % adminid) | ||||||
|     run(host=host, port=port) |     run(host=host, port=port) | ||||||
| 
 | 
 | ||||||
| def client(host, port): | def client(host, port): | ||||||
|  | @ -176,8 +202,8 @@ def client(host, port): | ||||||
| 
 | 
 | ||||||
|     # TODO: write a simple client with urllib2, for now use curl from command line |     # TODO: write a simple client with urllib2, for now use curl from command line | ||||||
|     print "[ERROR] Not yet implemented, use curl from command line instead for now, for example:" |     print "[ERROR] Not yet implemented, use curl from command line instead for now, for example:" | ||||||
|     print "\n\t$ curl --proxy http://127.0.0.1:8080 http://%s:%s/session/new" % (host, port) |     print "\n\t$ curl --proxy http://127.0.0.1:8080 http://127.0.0.1:%s/task/new" % port | ||||||
|     print "\t$ curl --proxy http://127.0.0.1:8080 -H \"Content-Type: application/json\" -X POST -d '{\"sessionid\": \"<admin session id>\"}' http://%s:%d/session/list\n" % (host, port) |     print "\t$ curl --proxy http://127.0.0.1:8080 -H \"Content-Type: application/json\" -X POST -d '{\"targetUrl\": \"<target URL>\"}' http://127.0.0.1:%d/scan/<task ID>\n" % port | ||||||
| 
 | 
 | ||||||
| if __name__ == "__main__": | if __name__ == "__main__": | ||||||
|     """ |     """ | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user