Skip to content

Commit d8326bc

Browse files
committed
First commit
0 parents  commit d8326bc

2 files changed

Lines changed: 346 additions & 0 deletions

File tree

report.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#!/usr/bin/env python
2+
#-*- coding: utf-8 -*-
3+
4+
'''
5+
[{u'status': 1,
6+
u'type': 0,
7+
u'value': [{u'dbms': u'MySQL',
8+
u'suffix': u'',
9+
u'clause': [1],
10+
u'ptype': 1,
11+
u'dbms_version': [u'> 5.0.11'],
12+
u'prefix': u'',
13+
u'place': u'GET',
14+
u'data': {u'1': {u'comment': u'',
15+
u'matchRatio': None,
16+
u'title': u'AND boolean-based blind - WHERE or HAVING clause',
17+
u'templatePayload': None,
18+
u'vector': u'AND [INFERENCE]',
19+
u'where': 1,
20+
u'payload': u'id=1 AND 6981=6981'},
21+
u'3': {u'comment': u'#',
22+
u'matchRatio': None,
23+
u'title': u'MySQL UNION query (NULL) - 1 to 20 columns',
24+
u'templatePayload': None, u'vector': [0, 1, u'#', u'', u'', u'NULL', 1, False],
25+
u'where': 1,
26+
u'payload': u'id=1 UNION ALL SELECT CONCAT(0x716b726771,0x54577443486b6268564d,0x7165697971)#'},
27+
u'5': {u'comment': u'',
28+
u'matchRatio': None,
29+
u'title': u'MySQL > 5.0.11 AND time-based blind',
30+
u'templatePayload': None,
31+
u'vector': u'AND [RANDNUM]=IF(([INFERENCE]),SLEEP([SLEEPTIME]),[RANDNUM])',
32+
u'where': 1,
33+
u'payload': u'id=1 AND SLEEP([SLEEPTIME])'}
34+
},
35+
u'conf': {u'string': None,
36+
u'notString': None,
37+
u'titles': False,
38+
u'regexp': None,
39+
u'textOnly': False,
40+
u'optimize': False},
41+
u'parameter': u'id',
42+
u'os': None}]
43+
}] '''
44+
45+
class Value(object):
46+
def __init__(self):
47+
pass
48+
49+
class Data(object):
50+
def __init__(self):
51+
pass
52+
53+
class Report(object):
54+
def __init__(self, r_data):
55+
raw_data = r_data[0] if r_data else None
56+
if raw_data:
57+
self.status = raw_data['status']
58+
self.type = raw_data['type']
59+
self.value = Value(raw_data['value'])
60+
61+
def __str__(self):
62+
return "<status:%s,type:%s,value:%s>"% (self.status,self.type,type(self.value))

sqlmapcli.py

Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
#!/usr/bin/env python
2+
3+
# RESTful API for sqlmap server
4+
# ---------------------------------------------------------------
5+
# @get("/task/new")
6+
# @get("/task/<taskid>/delete")
7+
8+
# @get("/admin/<taskid>/list")
9+
# @get("/admin/<taskid>/flush")
10+
11+
# @post("/scan/<taskid>/start")
12+
# @get("/scan/<taskid>/stop")
13+
# @get("/scan/<taskid>/kill")
14+
# @get("/scan/<taskid>/status")
15+
# @get("/scan/<taskid>/data")
16+
17+
# @get("/scan/<taskid>/log/<start>/<end>")
18+
# @get("/scan/<taskid>/log")
19+
20+
# @get("/option/<taskid>/list")
21+
# @post("/option/<taskid>/get")
22+
# @post("/option/<taskid>/set")
23+
24+
# @get("/download/<taskid>/<target>/<filename:path>")
25+
# ---------------------------------------------------------------
26+
27+
import sys
28+
import time
29+
import json
30+
import logging
31+
import requests
32+
from report import Report
33+
from threading import Timer
34+
from urlparse import urljoin
35+
36+
logger = logging.getLogger(__file__)
37+
logger.addHandler(logging.StreamHandler(sys.stdout))
38+
logger.setLevel(logging.DEBUG)
39+
40+
RESTAPI_SERVER_HOST = "127.0.0.1"
41+
RESTAPI_SERVER_PORT = 8775
42+
43+
44+
class OperationFailed(Exception):
45+
def __init__(self, msg="???"):
46+
self.msg = msg
47+
48+
def __str__(self):
49+
return "<OperationFailed:%s>" % self.msg
50+
51+
52+
class SqlmapClient(object):
53+
"""
54+
Sqlmap REST-JSON API client
55+
"""
56+
def __init__(self, host=RESTAPI_SERVER_HOST, port=RESTAPI_SERVER_PORT):
57+
self.addr = "http://%s:%d" % (host, port)
58+
self.options = dict()
59+
logger.info("Starting REST-JSON API client to '%s'...\n", self.addr)
60+
61+
def create_task(self):
62+
try:
63+
resp = requests.get(urljoin(self.addr, "/task/new"))
64+
except requests.RequestException, e:
65+
raise e
66+
if resp.status_code == 200:
67+
r = resp.json()
68+
if r.get("success", False):
69+
taskid = r.get("taskid", None)
70+
logger.info(">>> Create task<%s>", taskid)
71+
return taskid
72+
else:
73+
raise OperationFailed("Failed to create task")
74+
else:
75+
raise OperationFailed("Failed to create task, Response<%d>" % resp.status_code)
76+
77+
def delete_task(self, taskid):
78+
uri = "".join(["/task/", taskid, "/delete"])
79+
try:
80+
resp = requests.get(urljoin(self.addr, uri))
81+
except requests.RequestException, e:
82+
raise e
83+
if resp.status_code == 200:
84+
r = resp.json()
85+
if r.get("success", False):
86+
logger.info(">>> Delete task<%s>", taskid)
87+
return True
88+
else:
89+
raise OperationFailed("Failed to delete task<%s>:%s" % (taskid, r.get("message")))
90+
else:
91+
raise OperationFailed("Failed to delete task<%s>, Response<%s>" % (taskid, resp.status_code))
92+
93+
def admin_list(self, taskid, action):
94+
uri = "".join(["/admin/", taskid, "/list"])
95+
try:
96+
resp = requests.get(urljoin(self.addr, uri))
97+
except requests.RequestException, e:
98+
raise e
99+
if resp.status_code == 200:
100+
r = resp.json()
101+
if r.get("success", False):
102+
ntask, tasks = r.get("tasks_num"), r.get("tasks")
103+
logger.info("Admin list %d tasks:%s", ntask, tasks)
104+
return ntask, tasks
105+
else:
106+
raise OperationFailed("Failed to list tasks:%s" % r.get("message"))
107+
else:
108+
raise OperationFailed("Failed to list tasks, Response<%s>" % resp.status_code)
109+
110+
def admin_flush(self, taskid):
111+
uri = "".join(["/admin/", taskid, "/flush"])
112+
try:
113+
resp = requests.get(urljoin(self.addr, uri))
114+
except requests.RequestException, e:
115+
raise e
116+
if resp.status_code == 200:
117+
r = resp.json()
118+
if r.get("success", False):
119+
logger.info("Admin flush tasks Success")
120+
return True
121+
else:
122+
raise OperationFailed("Admin flush tasks Failed: %s" % r.get("message"))
123+
else:
124+
raise OperationFailed("Admin flush tasks Failed, Response<%s>" % resp.status_code)
125+
126+
127+
def start_scan(self, taskid):
128+
uri = "".join(["/scan/", taskid, "/start"])
129+
headers = {"content-type":"application/json"}
130+
131+
try:
132+
resp = requests.post(urljoin(self.addr, uri),
133+
data=json.dumps(self.options),
134+
headers=headers)
135+
except requests.RequestException, e:
136+
raise e
137+
if resp.status_code == 200:
138+
r = resp.json()
139+
if r.get("success", False):
140+
engineid = r.get("engineid")
141+
logger.info("Start task<%s>, EngineID:%s", taskid, engineid)
142+
return engineid
143+
else:
144+
raise OperationFailed("Failed to start task<%s>:%s" % (taskid, r.get("message")))
145+
else:
146+
raise OperationFailed("Failed to start task<%s>,Response<%s>" % (taskid, resp.status_code))
147+
148+
def stop_scan(self, taskid):
149+
uri = "".join(["/scan/", taskid, "/stop"])
150+
try:
151+
resp = requests.get(urljoin(self.addr, uri))
152+
except requests.RequestException, e:
153+
raise e
154+
if resp.status_code == 200:
155+
r = resp.json()
156+
if r.get("success", False):
157+
logger.info("Stop task<%s>", taskid)
158+
return True
159+
else:
160+
raise OperationFailed("Failed to stop task<%s>:%s" % (taskid, r.get("message")))
161+
else:
162+
raise OperationFailed("Failed to stop task<%s>,Response<%s>" % (taskid, resp.status_code))
163+
164+
def kill_scan(self, taskid):
165+
uri = "".join(["/scan/", taskid, "/kill"])
166+
try:
167+
resp = requests.get(urljoin(self.addr, uri))
168+
except requests.RequestException, e:
169+
raise e
170+
if resp.status_code == 200:
171+
r = resp.json()
172+
if r.get("success", False):
173+
logger.info("Kill task<%s>", taskid)
174+
return True
175+
else:
176+
raise OperationFailed("Failed to kill task<%s>:%s" % (taskid, r.get("message")))
177+
else:
178+
raise OperationFailed("Failed to kill task<%s>,Response<%s>" % (taskid, resp.status_code))
179+
180+
181+
def get_scan_status(self, taskid):
182+
uri = "".join(["/scan/", taskid, "/status"])
183+
try:
184+
resp = requests.get(urljoin(self.addr, uri))
185+
except requests.RequestException, e:
186+
raise e
187+
if resp.status_code == 200:
188+
r = resp.json()
189+
if r.get("success", False):
190+
status, retcode = r.get("status"), r.get("returncode")
191+
logger.info("Task<%s> status: %s", taskid, status)
192+
return retcode
193+
else:
194+
raise OperationFailed("Failed to get task<%s> status:%s" % (taskid, r.get("message")))
195+
else:
196+
raise OperationFailed("Failed to get task<%s> status,Response<%s>" % (taskid, resp.status_code))
197+
198+
def get_scan_report(self, taskid):
199+
uri = "".join(["/scan/", taskid, "/status"])
200+
try:
201+
resp = requests.get(urljoin(self.addr, uri))
202+
except requests.RequestException, e:
203+
raise e
204+
if resp.status_code == 200:
205+
r = resp.json()
206+
if r.get("success", False):
207+
data, error = r.get("data"), r.get("error")
208+
logger.info("Get task<%s> report, error: %s", taskid, error)
209+
return data, error
210+
else:
211+
raise OperationFailed("Failed to get task<%s> report:%s" % (taskid, r.get("message")))
212+
else:
213+
raise OperationFailed("Failed to get task<%s> report,Response<%s>" % (taskid, resp.status_code))
214+
215+
def get_scan_log(self, taskid, start=None, end=None):
216+
raise NotImplementedError()
217+
218+
def set_option(self, key, value):
219+
self.options[key] = value
220+
return self
221+
222+
def get_option(self, key):
223+
raise NotImplementedError()
224+
225+
def list_option(self):
226+
raise NotImplementedError()
227+
228+
def download(self):
229+
raise NotImplementedError()
230+
231+
def run(self, taskid, url=None, timeout=None):
232+
233+
if url is not None:
234+
self.set_option("url", url)
235+
236+
if timeout:
237+
timer = Timer(timeout, self.ontimeout, (taskid,))
238+
timer.start()
239+
try:
240+
self.start_scan(taskid)
241+
retcode = self.get_scan_status(taskid)
242+
while retcode is None:
243+
time.sleep(5)
244+
retcode = self.get_scan_status(taskid)
245+
246+
if retcode == 0:
247+
data = self.get_scan_report(taskid)
248+
else:
249+
data = None
250+
if timeout:
251+
timer.cancel()
252+
except OperationFailed, e:
253+
if timeout:
254+
timer.cancel()
255+
raise e
256+
return Report(data)
257+
258+
def ontimeout(self, taskid):
259+
if self.get_scan_status(taskid) is None:
260+
self.kill_scan(taskid)
261+
262+
#######################################################################
263+
if __name__ == '__main__':
264+
265+
filepath = "result_test.txt"
266+
f = open(filepath, "r")
267+
268+
client = SqlmapClient()
269+
try:
270+
taskid = client.create_task()
271+
except Exception, e:
272+
logger.error("Failed to create task: %s",e)
273+
sys.exit(1)
274+
client.set_option("dbms", "mysql") # .set_option("bulkFile", filepath)
275+
for url in f.readlines():
276+
try:
277+
res = client.run(taskid, url, 20)
278+
except Exception, e:
279+
logger.error(e)
280+
continue
281+
282+
client.delete_task(taskid)
283+
284+
f.close()

0 commit comments

Comments
 (0)