Skip to content
This repository was archived by the owner on Apr 17, 2021. It is now read-only.

Commit 0a4aeff

Browse files
committed
WIP: sqlmap interface
1 parent 35031e7 commit 0a4aeff

File tree

7 files changed

+206
-29
lines changed

7 files changed

+206
-29
lines changed

autosqli/execute.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from autosqli.satanize import satanize_for_bash
55

66

7-
def execute(command, cwd=None, timeout=None, yes=None):
7+
def execute(command, cwd=None, timeout=None, yes=None, background=False):
88
""" must be an array
99
returns the stdout of command
1010
command is an array of args

autosqli/save.py

+21-21
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,6 @@
1212
save = {'targets': [], 'stage': stages.DORK_STAGE}
1313

1414

15-
def get_vulnerable_targets():
16-
""" returns all vulnerable targets from the save """
17-
vulnerable_list = []
18-
for target in save['targets']:
19-
if target.isVulnerable():
20-
vulnerable_list.append(target)
21-
22-
return vulnerable_list
23-
24-
25-
def get_invulnerable_targets():
26-
""" returns all invulnerable targets from the save """
27-
invulnerable_list = []
28-
for target in save['targets']:
29-
if not target.isVulnerable():
30-
invulnerable_list.append(target)
31-
32-
return invulnerable_list
33-
34-
3515
def writeSave():
3616
""" write in picle format the storage var """
3717
with open(SAVE_PATH, 'wb') as f:
@@ -104,7 +84,7 @@ def getUnwaffedTarget():
10484
return None
10585

10686

107-
def get_unsqlmapped_targets():
87+
def get_unsqlmapped_target():
10888
""" return a target which needs to be analyzed by sqlmap """
10989
""" if no target is found, return None """
11090
for target in save['targets']:
@@ -129,3 +109,23 @@ def updateTarget(target):
129109
def getTargets():
130110
""" return all targets from the save """
131111
return save['targets']
112+
113+
114+
def get_vulnerable_targets():
115+
""" returns all vulnerable targets from the save """
116+
vulnerable_list = []
117+
for target in save['targets']:
118+
if target.isVulnerable():
119+
vulnerable_list.append(target)
120+
121+
return vulnerable_list
122+
123+
124+
def get_invulnerable_targets():
125+
""" returns all invulnerable targets from the save """
126+
invulnerable_list = []
127+
for target in save['targets']:
128+
if not target.isVulnerable():
129+
invulnerable_list.append(target)
130+
131+
return invulnerable_list

autosqli/sqlmap_interface.py

+169-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,176 @@
11
# From AutoSQLi
2-
# tricky part here :)
2+
# Most parts of this file where took from here:
3+
# https://github.com/Ekultek/Zeus-Scanner/blob/master/lib/attacks/sqlmap_scan/__init__.py
4+
# Thanks to Ekultek (https://github.com/Ekultek) !
35

6+
import json
7+
import re
8+
import requests
9+
import psutil
10+
from multiprocessing import Process
411

5-
def sqlmap_url(url):
6-
pass
12+
from autosqli.execute import execute
13+
from autosqli import log
14+
15+
16+
def sqlmapapi_launch():
17+
""" launches sqlmapapi in another process """
18+
19+
def background():
20+
sta = execute(['python2.7', 'sqlmapapi.py', '-s'], 'sqlmap/', None,
21+
None)
22+
23+
if 'Address already in use' in sta:
24+
log.critical('sqlmapapi.py said: {}'.format(sta))
25+
26+
if 'bash' in sta:
27+
log.critical('bash error: {}'.format(sta))
28+
29+
p = Process(target=background)
30+
p.start()
31+
32+
33+
def sqlmapapi_check():
34+
""" verify if sqlmapi is launched, if not launch it """
35+
log.info("Checking if sqlmapapi is already launched")
36+
37+
launched = False
38+
launched = 'sqlmapapi.py' in str({p.pid: p.info for p in
39+
psutil.process_iter(attrs=['cmdline'])})
40+
if not launched:
41+
log.info("Launching sqlmapapi")
42+
sqlmapapi_launch()
43+
44+
45+
def sqlmap_url(url, options):
46+
""" return sqlmap results for a specific url and specified options """
47+
# check if sqlmapapi is available
48+
sqlmapapi_check()
49+
50+
# create the new api interface
51+
sqlmap = SqlmapHook(url)
52+
53+
# init a new scan ( create it, but don't launch it )
54+
sqlmap.init_new_scan()
55+
56+
scan_id = sqlmap.get_scan_id()
57+
log.debug("Launching a sqlmap scan for {} (id: {})".format(url, scan_id))
58+
sqlmap.start_scan(scan_id, options)
59+
# TODO: wait for scan to finish
60+
pass # FIXME: not done
761

862

963
def sqlmap_target(target):
64+
""" add sqlmap details to a Target """
65+
report = sqlmap_url(target.url)
66+
log.debug("report: {}".format(report))
1067
pass
68+
69+
70+
class SqlmapHook(object):
71+
72+
"""
73+
Sqlmap API hook, will process API requests, and output API data
74+
"""
75+
76+
def __init__(self, to_scan, port=None, api_con="http://127.0.0.1:{}",
77+
default_port=8775):
78+
self.to_scan = to_scan
79+
self.port = port or default_port
80+
self.headers = {"Content-Type": "application/json"}
81+
self.connection = api_con.format(self.port)
82+
self.commands = {
83+
"init": "/task/new",
84+
"id": "/admin/0/list",
85+
"start": "/scan/{}/start",
86+
"status": "/scan/{}/status",
87+
"log": "/scan/{}/log"
88+
}
89+
90+
def init_new_scan(self):
91+
"""
92+
create a new API scan
93+
"""
94+
new_scan_url = "{}{}".format(self.connection, self.commands["init"])
95+
return requests.get(new_scan_url, params=self.headers)
96+
97+
def get_scan_id(self, split_by=16):
98+
"""
99+
get the ID of the current API scan
100+
"""
101+
# current_scan_id = None
102+
id_re = re.compile(r"[a-fA-F0-9]{16}")
103+
api_id_url = "{}{}".format(self.connection, self.commands["id"])
104+
req = requests.get(api_id_url)
105+
to_check = str(json.loads(req.content)["tasks"]).lower()
106+
return ''.join(id_re.findall(to_check))
107+
108+
def start_scan(self, api_id, opts=None):
109+
"""
110+
start the API scan
111+
"""
112+
start_scan_url = "{}{}".format(
113+
self.connection,
114+
self.commands["start"].format(api_id)
115+
)
116+
data_dict = {"url": self.to_scan}
117+
if opts is not None:
118+
for i in range(0, len(opts)):
119+
data_dict[opts[i][0]] = opts[i][1]
120+
post_data = json.dumps(data_dict)
121+
# req = urllib2.Request(
122+
# start_scan_url,
123+
# data=post_data,
124+
# headers=self.headers
125+
# )
126+
requests.post(
127+
start_scan_url,
128+
data=post_data,
129+
headers=self.headers
130+
)
131+
132+
def show_sqlmap_log(self, api_id):
133+
"""
134+
show the sqlmap log during the API scan
135+
"""
136+
running_status_url = "{}{}".format(
137+
self.connection,
138+
self.commands["status"].format(api_id)
139+
)
140+
running_log_url = "{}{}".format(
141+
self.connection,
142+
self.commands["log"].format(api_id)
143+
)
144+
status_req = requests.get(running_status_url)
145+
status_json = json.loads(status_req.content)
146+
current_status = status_json["status"]
147+
if current_status != "running":
148+
log.critical(
149+
"sqlmap API failed to start the run, check the client and see "
150+
"what the problem is and try again"
151+
)
152+
already_displayed = set()
153+
while current_status == "running":
154+
# while the current status evaluates to `running`
155+
# we can load the JSON data and output the log information
156+
# we will skip over information that has already been provided
157+
# by using the already displayed container set.
158+
# this will allow us to only output information that we
159+
# have not seen yet.
160+
current_status = json.loads(
161+
requests.get(running_status_url).content
162+
)["status"]
163+
log_req = requests.get(running_log_url)
164+
log_json = json.loads(log_req.content)
165+
for i in range(0, len(log_json["log"])):
166+
if log_json["log"][i]["message"] in already_displayed:
167+
pass
168+
else:
169+
print(
170+
"sqlmap> [{} {}] {}".format(
171+
log_json["log"][i]["time"],
172+
log_json["log"][i]["level"],
173+
log_json["log"][i]["message"]
174+
)
175+
)
176+
already_displayed.add(log_json["log"][i]["message"])

autosqli/sqlmap_stage.py

+11-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
# From AutoSQLi
2+
from autosqli import save
3+
from autosqli import sqlmap_interface
24

35

4-
def sqlmap_stage(args, targets):
6+
def sqlmap_stage(args):
57
""" do a sqlmap scan on all the targets """
6-
pass
8+
9+
while True:
10+
with save.get_unsqlmapped_target() as target:
11+
# there is no not sqlmapped target remaining
12+
if target is None:
13+
break
14+
15+

requirements.txt

+2
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
argparse
2+
psutil
3+
requests

0 commit comments

Comments
 (0)