@@ -60,10 +60,10 @@ def __init__(self):
6060
6161 def create (self ):
6262 _ , self .database = tempfile .mkstemp (prefix = "sqlmapipc-" , text = False )
63- logger .info ("IPC database is %s" % self .database )
63+ logger .debug ("IPC database: %s" % self .database )
6464
6565 def connect (self ):
66- self .connection = sqlite3 .connect (self .database , timeout = 1 , isolation_level = None )
66+ self .connection = sqlite3 .connect (self .database , timeout = 3 , isolation_level = None )
6767 self .cursor = self .connection .cursor ()
6868
6969 def disconnect (self ):
@@ -132,18 +132,28 @@ def clean_filesystem(self):
132132 shutil .rmtree (self .output_directory )
133133
134134 def engine_start (self ):
135- self .process = Popen ("python sqlmap.py --pickled-options %s" % base64pickle (self .options ), shell = True , stdin = PIPE )
135+ self .process = Popen ("python sqlmap.py --pickled-options %s" % base64pickle (self .options ), shell = True , stdin = PIPE , close_fds = False )
136136
137137 def engine_stop (self ):
138138 if self .process :
139- self .process .terminate ()
139+ return self .process .terminate ()
140+ else :
141+ return None
140142
141143 def engine_kill (self ):
142144 if self .process :
143- self .process .kill ()
145+ return self .process .kill ()
146+ else :
147+ return None
148+
149+ def engine_get_id (self ):
150+ if self .process :
151+ return self .process .pid
152+ else :
153+ return None
144154
145- def engine_get_pid (self ):
146- return self .processid . pid
155+ def engine_has_terminated (self ):
156+ return isinstance ( self .process . returncode , int ) == True
147157
148158# Wrapper functions for sqlmap engine
149159class StdDbOut (object ):
@@ -162,9 +172,13 @@ def __init__(self, taskid, messagetype="stdout"):
162172
163173 def write (self , value , status = None , content_type = None ):
164174 if self .messagetype == "stdout" :
165- conf .database_cursor .execute ("INSERT INTO data VALUES(NULL, ?, ?, ?, ?)" , (self .taskid , status , content_type , jsonize (value )))
175+ #conf.database_cursor.execute("INSERT INTO data VALUES(NULL, ?, ?, ?, ?)",
176+ # (self.taskid, status, content_type, base64pickle(value)))
177+ conf .database_cursor .execute ("INSERT INTO data VALUES(NULL, ?, ?, ?, ?)" ,
178+ (self .taskid , status , content_type , jsonize (value )))
166179 else :
167- conf .database_cursor .execute ("INSERT INTO errors VALUES(NULL, ?, ?)" , (self .taskid , value ))
180+ conf .database_cursor .execute ("INSERT INTO errors VALUES(NULL, ?, ?)" ,
181+ (self .taskid , str (value ) if value else "" ))
168182
169183 def flush (self ):
170184 pass
@@ -182,8 +196,7 @@ def emit(self, record):
182196 communication with the parent process
183197 """
184198 conf .database_cursor .execute ("INSERT INTO logs VALUES(NULL, ?, ?, ?, ?)" ,
185- (conf .taskid , time .strftime ("%X" ), record .levelname ,
186- record .msg % record .args if record .args else record .msg ))
199+ (conf .taskid , time .strftime ("%X" ), record .levelname , record .msg % record .args if record .args else record .msg ))
187200
188201def setRestAPILog ():
189202 if hasattr (conf , "api" ):
@@ -257,35 +270,44 @@ def task_new():
257270 taskid = hexencode (os .urandom (8 ))
258271 tasks [taskid ] = Task (taskid )
259272
273+ logger .debug ("Created new task ID: %s" % taskid )
274+
260275 return jsonize ({"taskid" : taskid })
261276
262- @get ("/task/<taskid>/destroy " )
263- def task_destroy (taskid ):
277+ @get ("/task/<taskid>/delete " )
278+ def task_delete (taskid ):
264279 """
265- Destroy own task ID
280+ Delete own task ID
266281 """
267282 if taskid in tasks :
268283 tasks [taskid ].clean_filesystem ()
269284 tasks .pop (taskid )
285+
286+ logger .debug ("Deleted task ID: %s" % taskid )
287+
270288 return jsonize ({"success" : True })
271289 else :
272290 abort (500 , "Invalid task ID" )
273291
274- # Admin's methods
275- @get ("/task/<taskid>/list" )
292+ ###################
293+ # Admin functions #
294+ ###################
295+
296+ @get ("/admin/<taskid>/list" )
276297def task_list (taskid ):
277298 """
278- List all active tasks
299+ List task poll
279300 """
280301 if is_admin (taskid ):
281- return jsonize ({"tasks" : tasks })
302+ logger .debug ("Listed task poll" )
303+ return jsonize ({"tasks" : tasks , "tasks_num" : len (tasks )})
282304 else :
283305 abort (401 )
284306
285- @get ("/task /<taskid>/flush" )
307+ @get ("/admin /<taskid>/flush" )
286308def task_flush (taskid ):
287309 """
288- Flush task spool (destroy all tasks)
310+ Flush task spool (delete all tasks)
289311 """
290312 global tasks
291313
@@ -294,6 +316,7 @@ def task_flush(taskid):
294316 tasks [task ].clean_filesystem ()
295317
296318 tasks = dict ()
319+ logger .debug ("Flushed task poll" )
297320 return jsonize ({"success" : True })
298321 else :
299322 abort (401 )
@@ -302,20 +325,7 @@ def task_flush(taskid):
302325# sqlmap core interact functions #
303326##################################
304327
305- # Admin's methods
306- @get ("/status/<taskid>" )
307- def status (taskid ):
308- """
309- Verify the status of the API as well as the core
310- """
311-
312- if is_admin (taskid ):
313- tasks_num = len (tasks )
314- return jsonize ({"tasks" : tasks_num })
315- else :
316- abort (401 )
317-
318- # Functions to handle options
328+ # Handle task's options
319329@get ("/option/<taskid>/list" )
320330def option_list (taskid ):
321331 """
@@ -324,7 +334,7 @@ def option_list(taskid):
324334 if taskid not in tasks :
325335 abort (500 , "Invalid task ID" )
326336
327- return jsonize (tasks [taskid ].get_options ())
337+ return jsonize ({ "options" : tasks [taskid ].get_options ()} )
328338
329339@post ("/option/<taskid>/get" )
330340def option_get (taskid ):
@@ -339,7 +349,7 @@ def option_get(taskid):
339349 if option in tasks [taskid ]:
340350 return jsonize ({option : tasks [taskid ].get_option (option )})
341351 else :
342- return jsonize ({option : None })
352+ return jsonize ({option : "Not set" })
343353
344354@post ("/option/<taskid>/set" )
345355def option_set (taskid ):
@@ -356,7 +366,7 @@ def option_set(taskid):
356366
357367 return jsonize ({"success" : True })
358368
359- # Function to handle scans
369+ # Handle scans
360370@post ("/scan/<taskid>/start" )
361371def scan_start (taskid ):
362372 """
@@ -375,12 +385,12 @@ def scan_start(taskid):
375385 tasks [taskid ].set_output_directory ()
376386
377387 # Launch sqlmap engine in a separate thread
378- logger .debug ("starting a scan for task ID %s" % taskid )
388+ logger .debug ("Starting a scan for task ID %s" % taskid )
379389
380390 # Launch sqlmap engine
381391 tasks [taskid ].engine_start ()
382392
383- return jsonize ({"success" : True })
393+ return jsonize ({"success" : True , "engineid" : tasks [ taskid ]. engine_get_id () })
384394
385395@get ("/scan/<taskid>/stop" )
386396def scan_stop (taskid ):
@@ -406,21 +416,6 @@ def scan_kill(taskid):
406416
407417 return jsonize ({"success" : tasks [taskid ].engine_kill ()})
408418
409- @get ("/scan/<taskid>/delete" )
410- def scan_delete (taskid ):
411- """
412- Delete a scan and corresponding temporary output directory and IPC database
413- """
414- global tasks
415-
416- if taskid not in tasks :
417- abort (500 , "Invalid task ID" )
418-
419- scan_stop (taskid )
420- tasks [taskid ].clean_filesystem ()
421-
422- return jsonize ({"success" : True })
423-
424419@get ("/scan/<taskid>/data" )
425420def scan_data (taskid ):
426421 """
@@ -436,7 +431,8 @@ def scan_data(taskid):
436431
437432 # Read all data from the IPC database for the taskid
438433 for status , content_type , value in db .execute ("SELECT status, content_type, value FROM data WHERE taskid = ? ORDER BY id ASC" , (taskid ,)):
439- json_data_message .append ([status , content_type , dejsonize (value )])
434+ #json_data_message.append({"status": status, "type": content_type, "value": base64unpickle(value)})
435+ json_data_message .append ({"status" : status , "type" : content_type , "value" : dejsonize (value )})
440436
441437 # Read all error messages from the IPC database
442438 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):
515511 global db
516512
517513 adminid = hexencode (os .urandom (16 ))
514+
515+ logger .info ("Running REST-JSON API server at '%s:%d'.." % (host , port ))
516+ logger .info ("Admin ID: %s" % adminid )
517+
518+ # Initialize IPC database
518519 db = Database ()
519520 db .initialize ()
520521
521- logger .info ("running REST-JSON API server at '%s:%d'.." % (host , port ))
522- logger .info ("the admin task ID is: %s" % adminid )
523-
524522 # Run RESTful API
525- run (host = host , port = port , quiet = False , debug = False )
523+ run (host = host , port = port , quiet = True , debug = False )
526524
527525def client (host = RESTAPI_SERVER_HOST , port = RESTAPI_SERVER_PORT ):
528526 """
529527 REST-JSON API client
530528 """
531529 addr = "http://%s:%d" % (host , port )
532- logger .info ("starting debug REST-JSON client to '%s'..." % addr )
530+ logger .info ("Starting REST-JSON API client to '%s'..." % addr )
533531
534532 # TODO: write a simple client with requests, for now use curl from command line
535- logger .error ("not yet implemented, use curl from command line instead for now, for example:" )
533+ logger .error ("Not yet implemented, use curl from command line instead for now, for example:" )
536534 print "\n \t $ curl http://%s:%d/task/new" % (host , port )
537535 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 )
538536 print "\t $ curl http://%s:%d/scan/:taskid/output" % (host , port )
0 commit comments