enhanced RESTful API to support JSON requests and improved standalone client/server skeleton (issue #297)

This commit is contained in:
Bernardo Damele 2012-12-14 12:01:13 +00:00
parent 156a291e2d
commit 90d5696b25

View File

@ -5,35 +5,66 @@ Copyright (c) 2006-2012 sqlmap developers (http://sqlmap.org/)
See the file 'doc/COPYING' for copying permission See the file 'doc/COPYING' for copying permission
""" """
import sys import argparse
import json
import os import os
import sys
from extra.bottle.bottle import abort, error, get, post, request, run, template, debug try:
from lib.controller.controller import start import simplejson as json
from lib.core.convert import hexencode except ImportError:
from lib.core.datatype import AttribDict import json
from lib.core.data import cmdLineOptions
from lib.core.data import kb
from lib.core.data import logger
from lib.core.exception import SqlmapMissingDependence
from lib.core.option import init
from lib.core.settings import UNICODE_ENCODING
from lib.core.settings import RESTAPI_SERVER_PORT
try:
from extra.bottle.bottle import abort
from extra.bottle.bottle import debug
from extra.bottle.bottle import error
from extra.bottle.bottle import get
from extra.bottle.bottle import post
from extra.bottle.bottle import request
from extra.bottle.bottle import response
from extra.bottle.bottle import Response
from extra.bottle.bottle import run
from extra.bottle.bottle import static_file
from extra.bottle.bottle import template
except ImportError:
try:
from bottle import *
except ImportError, e:
print "[x] '%s'" % str(e)
sys.exit(1)
try:
sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), "..", ".."))
from lib.controller.controller import start
from lib.core.convert import hexencode
from lib.core.datatype import AttribDict
from lib.core.data import cmdLineOptions
from lib.core.data import kb
from lib.core.data import logger
from lib.core.exception import SqlmapMissingDependence
from lib.core.option import init
from lib.core.settings import UNICODE_ENCODING
from lib.core.settings import RESTAPI_SERVER_PORT
except ImportError:
RESTAPI_SERVER_PORT = 8775
# local global variables # local global variables
session_ids = [] session_ids = []
admin_id = "" admin_id = ""
Response(headers={"X-Frame-Options": "sameorigin", "X-XSS-Protection": "1; mode=block"})
# 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, indent=4)
return json.dumps(data, sort_keys=False)
def is_admin(session_id): def is_admin(session_id):
global admin_id global admin_id
#print "[INFO] Admin ID: %s" % admin_id
#print "[INFO] Session ID: %s" % session_id
if admin_id != session_id: if admin_id != session_id:
return False return False
else: else:
@ -55,6 +86,7 @@ def error404(error):
def error405(error): def error405(error):
return "Method not allowed" return "Method not allowed"
@error(500) # Internal Server Error @error(500) # Internal Server Error
def error500(error): def error500(error):
return "Internal server error" return "Internal server error"
@ -73,6 +105,7 @@ def session_new():
global session_ids global session_ids
session_id = hexencode(os.urandom(32)) session_id = hexencode(os.urandom(32))
session_ids.append(session_id) session_ids.append(session_id)
response.content_type = "application/json; charset=UTF-8"
return jsonize({"sessionid": session_id}) return jsonize({"sessionid": session_id})
@ -81,9 +114,7 @@ def session_destroy():
""" """
Destroy own session token Destroy own session token
""" """
# TODO: replace use of request.forms with JSON session_id = request.json.get("sessionid", "")
session_id = request.forms.get("sessionid", "")
#<sessionid:re:x[0-9a-fA-F]+>
if session_id in session_ids: if session_id in session_ids:
session_ids.remove(session_id) session_ids.remove(session_id)
return "Done" return "Done"
@ -96,25 +127,37 @@ def session_list():
""" """
List all active sessions List all active sessions
""" """
# TODO: replace use of request.forms with JSON if is_admin(request.json.get("sessionid", "")):
if is_admin(request.forms.get("sessionid", "")): response.content_type = "application/json; charset=UTF-8"
return jsonize({"sessions": session_ids}) return jsonize({"sessions": session_ids})
else: else:
abort(401) abort(401)
@get("/session/flush") @post("/session/flush")
def session_flush(): def session_flush():
""" """
Flush session spool (destroy all sessions) Flush session spool (destroy all sessions)
""" """
global session_ids global session_ids
if is_admin(request.forms.get("sessionid", "")): if is_admin(request.json.get("sessionid", "")):
session_ids = [] session_ids = []
else: else:
abort(401) abort(401)
@post("/download/<target>/<filename:path>")
def download(target, filename):
"""
Download a certain file from the file system
"""
path = os.path.join(paths.SQLMAP_OUTPUT_PATH, target)
if os.path.exists(path):
return static_file(filename, root=path)
else:
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
@ -126,9 +169,28 @@ def restAPIrun(host="0.0.0.0", port=RESTAPI_SERVER_PORT):
logger.info("The admin session ID is: %s" % admin_id) logger.info("The admin session ID is: %s" % admin_id)
run(host=host, port=port) run(host=host, port=port)
def client(host, port):
if __name__ == "__main__": addr = "http://%s:%d" % (host, port)
addr = "http://localhost:%d" % (int(sys.argv[1]) if len(sys.argv) > 1 else RESTAPI_SERVER_PORT) print "[INFO] Starting debug REST-JSON client to '%s'..." % addr
print "[i] Starting debug REST-JSON client to '%s'..." % addr
# 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 "\n\t$ curl --proxy http://127.0.0.1:8080 http://%s:%s/session/new" % (host, 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)
if __name__ == "__main__":
"""
Standalone REST-JSON API wrapper function
"""
parser = argparse.ArgumentParser()
parser.add_argument("-s", "--server", help="Act as a REST-JSON API server", default=RESTAPI_SERVER_PORT, action="store_true", required=False)
parser.add_argument("-c", "--client", help="Act as a REST-JSON API client", default=RESTAPI_SERVER_PORT, action="store_true", required=False)
parser.add_argument("-H", "--host", help="Host of the REST-JSON API server", default="0.0.0.0", action="store", required=False)
parser.add_argument("-p", "--port", help="Port of the the REST-JSON API server", default=RESTAPI_SERVER_PORT, action="store", required=False)
args = parser.parse_args()
if args.server is True:
restAPIrun(args.host, args.port)
elif args.client is True:
client(args.host, args.port)