FazBrowse GitHub Viewer
|
Trending
|
URL:
|
Home
Tools:
[Download Repo ZIP]
[View Raw Code]
[Original HTTPS Page]
sqlmap/lib/utils/api.py at master · feixiang8418/sqlmap · GitHub
feixiang8418
/
sqlmap
Public
forked from
sqlmapproject/sqlmap
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Pull requests
0
Actions
Projects
Wiki
Security and quality
0
Insights
Additional navigation options
Code
Pull requests
Actions
Projects
Wiki
Security and quality
Insights
Expand file tree
Breadcrumbs
sqlmap
/
lib
/
utils
/
api.py
Copy path
More file actions
More file actions
Latest commit
History
History
History
671 lines (529 loc) · 21.9 KB
Breadcrumbs
sqlmap
/
lib
/
utils
/
api.py
Copy path
File metadata and controls
671 lines (529 loc) · 21.9 KB
Raw
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Copyright (c) 2006-2014 sqlmap developers (http://sqlmap.org/)
See the file 'doc/COPYING' for copying permission
"""
import
logging
import
os
import
shutil
import
sqlite3
import
sys
import
tempfile
import
time
from
subprocess
import
PIPE
from
lib
.
core
.
common
import
unArrayizeValue
from
lib
.
core
.
convert
import
base64pickle
from
lib
.
core
.
convert
import
hexencode
from
lib
.
core
.
convert
import
dejsonize
from
lib
.
core
.
convert
import
jsonize
from
lib
.
core
.
data
import
conf
from
lib
.
core
.
data
import
kb
from
lib
.
core
.
data
import
paths
from
lib
.
core
.
data
import
logger
from
lib
.
core
.
datatype
import
AttribDict
from
lib
.
core
.
defaults
import
_defaults
from
lib
.
core
.
enums
import
CONTENT_STATUS
from
lib
.
core
.
enums
import
PART_RUN_CONTENT_TYPES
from
lib
.
core
.
log
import
LOGGER_HANDLER
from
lib
.
core
.
optiondict
import
optDict
from
lib
.
core
.
subprocessng
import
Popen
from
thirdparty
.
bottle
.
bottle
import
error
as
return_error
from
thirdparty
.
bottle
.
bottle
import
get
from
thirdparty
.
bottle
.
bottle
import
hook
from
thirdparty
.
bottle
.
bottle
import
post
from
thirdparty
.
bottle
.
bottle
import
request
from
thirdparty
.
bottle
.
bottle
import
response
from
thirdparty
.
bottle
.
bottle
import
run
RESTAPI_SERVER_HOST
=
"127.0.0.1"
RESTAPI_SERVER_PORT
=
8775
# global settings
class
DataStore
(
object
):
admin_id
=
""
current_db
=
None
tasks
=
dict
()
# API objects
class
Database
(
object
):
filepath
=
None
def
__init__
(
self
,
database
=
None
):
self
.
database
=
self
.
filepath
if
database
is
None
else
database
self
.
connection
=
None
self
.
cursor
=
None
def
connect
(
self
,
who
=
"server"
):
self
.
connection
=
sqlite3
.
connect
(
self
.
database
,
timeout
=
3
,
isolation_level
=
None
)
self
.
cursor
=
self
.
connection
.
cursor
()
logger
.
debug
(
"REST-JSON API %s connected to IPC database"
%
who
)
def
disconnect
(
self
):
self
.
cursor
.
close
()
self
.
connection
.
close
()
def
commit
(
self
):
self
.
connection
.
commit
()
def
execute
(
self
,
statement
,
arguments
=
None
):
if
arguments
:
self
.
cursor
.
execute
(
statement
,
arguments
)
else
:
self
.
cursor
.
execute
(
statement
)
if
statement
.
lstrip
().
upper
().
startswith
(
"SELECT"
):
return
self
.
cursor
.
fetchall
()
def
init
(
self
):
self
.
execute
(
"CREATE TABLE logs("
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
"taskid INTEGER, time TEXT, "
"level TEXT, message TEXT"
")"
)
self
.
execute
(
"CREATE TABLE data("
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
"taskid INTEGER, status INTEGER, "
"content_type INTEGER, value TEXT"
")"
)
self
.
execute
(
"CREATE TABLE errors("
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
"taskid INTEGER, error TEXT"
")"
)
class
Task
(
object
):
def
__init__
(
self
,
taskid
):
self
.
process
=
None
self
.
temporary_directory
=
False
self
.
output_directory
=
None
self
.
options
=
None
self
.
_original_options
=
None
self
.
initialize_options
(
taskid
)
def
initialize_options
(
self
,
taskid
):
datatype
=
{
"boolean"
:
False
,
"string"
:
None
,
"integer"
:
None
,
"float"
:
None
}
self
.
options
=
AttribDict
()
for
_
in
optDict
:
for
name
,
type_
in
optDict
[
_
].
items
():
type_
=
unArrayizeValue
(
type_
)
self
.
options
[
name
]
=
_defaults
.
get
(
name
,
datatype
[
type_
])
# Let sqlmap engine knows it is getting called by the API,
# the task ID and the file path of the IPC database
self
.
options
.
api
=
True
self
.
options
.
taskid
=
taskid
self
.
options
.
database
=
Database
.
filepath
# Enforce batch mode and disable coloring and ETA
self
.
options
.
batch
=
True
self
.
options
.
disableColoring
=
True
self
.
options
.
eta
=
False
self
.
_original_options
=
AttribDict
(
self
.
options
)
def
set_option
(
self
,
option
,
value
):
self
.
options
[
option
]
=
value
def
get_option
(
self
,
option
):
return
self
.
options
[
option
]
def
get_options
(
self
):
return
self
.
options
def
reset_options
(
self
):
self
.
options
=
AttribDict
(
self
.
_original_options
)
def
set_output_directory
(
self
):
if
self
.
get_option
(
"outputDir"
):
if
os
.
path
.
isdir
(
self
.
get_option
(
"outputDir"
)):
self
.
output_directory
=
self
.
get_option
(
"outputDir"
)
else
:
try
:
os
.
makedirs
(
self
.
get_option
(
"outputDir"
))
self
.
output_directory
=
self
.
get_option
(
"outputDir"
)
except
OSError
:
pass
if
not
self
.
output_directory
or
not
os
.
path
.
isdir
(
self
.
output_directory
):
self
.
output_directory
=
tempfile
.
mkdtemp
(
prefix
=
"sqlmapoutput-"
)
self
.
temporary_directory
=
True
self
.
set_option
(
"outputDir"
,
self
.
output_directory
)
def
clean_filesystem
(
self
):
if
self
.
output_directory
and
self
.
temporary_directory
:
shutil
.
rmtree
(
self
.
output_directory
)
def
engine_start
(
self
):
self
.
process
=
Popen
(
"python sqlmap.py --pickled-options %s"
%
base64pickle
(
self
.
options
),
shell
=
True
,
stdin
=
PIPE
,
close_fds
=
False
)
def
engine_stop
(
self
):
if
self
.
process
:
return
self
.
process
.
terminate
()
else
:
return
None
def
engine_process
(
self
):
return
self
.
process
def
engine_kill
(
self
):
if
self
.
process
:
return
self
.
process
.
kill
()
else
:
return
None
def
engine_get_id
(
self
):
if
self
.
process
:
return
self
.
process
.
pid
else
:
return
None
def
engine_get_returncode
(
self
):
if
self
.
process
:
self
.
process
.
poll
()
return
self
.
process
.
returncode
else
:
return
None
def
engine_has_terminated
(
self
):
return
isinstance
(
self
.
engine_get_returncode
(),
int
)
# Wrapper functions for sqlmap engine
class
StdDbOut
(
object
):
def
__init__
(
self
,
taskid
,
messagetype
=
"stdout"
):
# Overwrite system standard output and standard error to write
# to an IPC database
self
.
messagetype
=
messagetype
self
.
taskid
=
taskid
if
self
.
messagetype
==
"stdout"
:
sys
.
stdout
=
self
else
:
sys
.
stderr
=
self
def
write
(
self
,
value
,
status
=
CONTENT_STATUS
.
IN_PROGRESS
,
content_type
=
None
):
if
self
.
messagetype
==
"stdout"
:
if
content_type
is
None
:
if
kb
.
partRun
is
not
None
:
content_type
=
PART_RUN_CONTENT_TYPES
.
get
(
kb
.
partRun
)
else
:
# Ignore all non-relevant messages
return
output
=
conf
.
database_cursor
.
execute
(
"SELECT id, status, value FROM data WHERE taskid = ? AND content_type = ?"
,
(
self
.
taskid
,
content_type
))
# Delete partial output from IPC database if we have got a complete output
if
status
==
CONTENT_STATUS
.
COMPLETE
:
if
len
(
output
)
>
0
:
for
index
in
xrange
(
len
(
output
)):
conf
.
database_cursor
.
execute
(
"DELETE FROM data WHERE id = ?"
,
(
output
[
index
][
0
],))
conf
.
database_cursor
.
execute
(
"INSERT INTO data VALUES(NULL, ?, ?, ?, ?)"
,
(
self
.
taskid
,
status
,
content_type
,
jsonize
(
value
)))
if
kb
.
partRun
:
kb
.
partRun
=
None
elif
status
==
CONTENT_STATUS
.
IN_PROGRESS
:
if
len
(
output
)
==
0
:
conf
.
database_cursor
.
execute
(
"INSERT INTO data VALUES(NULL, ?, ?, ?, ?)"
,
(
self
.
taskid
,
status
,
content_type
,
jsonize
(
value
)))
else
:
new_value
=
"%s%s"
%
(
dejsonize
(
output
[
0
][
2
]),
value
)
conf
.
database_cursor
.
execute
(
"UPDATE data SET value = ? WHERE id = ?"
,
(
jsonize
(
new_value
),
output
[
0
][
0
]))
else
:
conf
.
database_cursor
.
execute
(
"INSERT INTO errors VALUES(NULL, ?, ?)"
,
(
self
.
taskid
,
str
(
value
)
if
value
else
""
))
def
flush
(
self
):
pass
def
close
(
self
):
pass
def
seek
(
self
):
pass
class
LogRecorder
(
logging
.
StreamHandler
):
def
emit
(
self
,
record
):
"""
Record emitted events to IPC database for asynchronous I/O
communication with the parent process
"""
conf
.
database_cursor
.
execute
(
"INSERT INTO logs VALUES(NULL, ?, ?, ?, ?)"
,
(
conf
.
taskid
,
time
.
strftime
(
"%X"
),
record
.
levelname
,
record
.
msg
%
record
.
args
if
record
.
args
else
record
.
msg
))
def
setRestAPILog
():
if
hasattr
(
conf
,
"api"
):
conf
.
database_cursor
=
Database
(
conf
.
database
)
conf
.
database_cursor
.
connect
(
"client"
)
# Set a logging handler that writes log messages to a IPC database
logger
.
removeHandler
(
LOGGER_HANDLER
)
LOGGER_RECORDER
=
LogRecorder
()
logger
.
addHandler
(
LOGGER_RECORDER
)
# Generic functions
def
is_admin
(
taskid
):
return
DataStore
.
admin_id
==
taskid
@
hook
(
"after_request"
)
def
security_headers
(
json_header
=
True
):
"""
Set some headers across all HTTP responses
"""
response
.
headers
[
"Server"
]
=
"Server"
response
.
headers
[
"X-Content-Type-Options"
]
=
"nosniff"
response
.
headers
[
"X-Frame-Options"
]
=
"DENY"
response
.
headers
[
"X-XSS-Protection"
]
=
"1; mode=block"
response
.
headers
[
"Pragma"
]
=
"no-cache"
response
.
headers
[
"Cache-Control"
]
=
"no-cache"
response
.
headers
[
"Expires"
]
=
"0"
if
json_header
:
response
.
content_type
=
"application/json; charset=UTF-8"
##############################
# HTTP Status Code functions #
##############################
@
return_error
(
401
)
# Access Denied
def
error401
(
error
=
None
):
security_headers
(
False
)
return
"Access denied"
@
return_error
(
404
)
# Not Found
def
error404
(
error
=
None
):
security_headers
(
False
)
return
"Nothing here"
@
return_error
(
405
)
# Method Not Allowed (e.g. when requesting a POST method via GET)
def
error405
(
error
=
None
):
security_headers
(
False
)
return
"Method not allowed"
@
return_error
(
500
)
# Internal Server Error
def
error500
(
error
=
None
):
security_headers
(
False
)
return
"Internal server error"
#############################
# Task management functions #
#############################
# Users' methods
@
get
(
"/task/new"
)
def
task_new
():
"""
Create new task ID
"""
taskid
=
hexencode
(
os
.
urandom
(
8
))
DataStore
.
tasks
[
taskid
]
=
Task
(
taskid
)
logger
.
debug
(
" [%s] Created new task"
%
taskid
)
return
jsonize
({
"success"
:
True
,
"taskid"
:
taskid
})
@
get
(
"/task/<taskid>/delete"
)
def
task_delete
(
taskid
):
"""
Delete own task ID
"""
if
taskid
in
DataStore
.
tasks
:
DataStore
.
tasks
[
taskid
].
clean_filesystem
()
DataStore
.
tasks
.
pop
(
taskid
)
logger
.
debug
(
"[%s] Deleted task"
%
taskid
)
return
jsonize
({
"success"
:
True
})
else
:
logger
.
warning
(
"[%s] Invalid task ID provided to task_delete()"
%
taskid
)
return
jsonize
({
"success"
:
False
,
"message"
:
"Invalid task ID"
})
###################
# Admin functions #
###################
@
get
(
"/admin/<taskid>/list"
)
def
task_list
(
taskid
):
"""
List task pull
"""
if
is_admin
(
taskid
):
logger
.
debug
(
"[%s] Listed task pool"
%
taskid
)
tasks
=
list
(
DataStore
.
tasks
)
return
jsonize
({
"success"
:
True
,
"tasks"
:
tasks
,
"tasks_num"
:
len
(
tasks
)})
else
:
logger
.
warning
(
"[%s] Unauthorized call to task_list()"
%
taskid
)
return
jsonize
({
"success"
:
False
,
"message"
:
"Unauthorized"
})
@
get
(
"/admin/<taskid>/flush"
)
def
task_flush
(
taskid
):
"""
Flush task spool (delete all tasks)
"""
if
is_admin
(
taskid
):
for
task
in
DataStore
.
tasks
:
DataStore
.
tasks
[
task
].
clean_filesystem
()
DataStore
.
tasks
=
dict
()
logger
.
debug
(
"[%s] Flushed task pool"
%
taskid
)
return
jsonize
({
"success"
:
True
})
else
:
logger
.
warning
(
"[%s] Unauthorized call to task_flush()"
%
taskid
)
return
jsonize
({
"success"
:
False
,
"message"
:
"Unauthorized"
})
##################################
# sqlmap core interact functions #
##################################
# Handle task's options
@
get
(
"/option/<taskid>/list"
)
def
option_list
(
taskid
):
"""
List options for a certain task ID
"""
if
taskid
not
in
DataStore
.
tasks
:
logger
.
warning
(
"[%s] Invalid task ID provided to option_list()"
%
taskid
)
return
jsonize
({
"success"
:
False
,
"message"
:
"Invalid task ID"
})
logger
.
debug
(
"[%s] Listed task options"
%
taskid
)
return
jsonize
({
"success"
:
True
,
"options"
:
DataStore
.
tasks
[
taskid
].
get_options
()})
@
post
(
"/option/<taskid>/get"
)
def
option_get
(
taskid
):
"""
Get the value of an option (command line switch) for a certain task ID
"""
if
taskid
not
in
DataStore
.
tasks
:
logger
.
warning
(
"[%s] Invalid task ID provided to option_get()"
%
taskid
)
return
jsonize
({
"success"
:
False
,
"message"
:
"Invalid task ID"
})
option
=
request
.
json
.
get
(
"option"
,
""
)
if
option
in
DataStore
.
tasks
[
taskid
].
options
:
logger
.
debug
(
"[%s] Retrieved value for option %s"
%
(
taskid
,
option
))
return
jsonize
({
"success"
:
True
,
option
:
DataStore
.
tasks
[
taskid
].
get_option
(
option
)})
else
:
logger
.
debug
(
"[%s] Requested value for unknown option %s"
%
(
taskid
,
option
))
return
jsonize
({
"success"
:
False
,
"message"
:
"Unknown option"
,
option
:
"not set"
})
@
post
(
"/option/<taskid>/set"
)
def
option_set
(
taskid
):
"""
Set an option (command line switch) for a certain task ID
"""
if
taskid
not
in
DataStore
.
tasks
:
logger
.
warning
(
"[%s] Invalid task ID provided to option_set()"
%
taskid
)
return
jsonize
({
"success"
:
False
,
"message"
:
"Invalid task ID"
})
for
option
,
value
in
request
.
json
.
items
():
DataStore
.
tasks
[
taskid
].
set_option
(
option
,
value
)
logger
.
debug
(
"[%s] Requested to set options"
%
taskid
)
return
jsonize
({
"success"
:
True
})
# Handle scans
@
post
(
"/scan/<taskid>/start"
)
def
scan_start
(
taskid
):
"""
Launch a scan
"""
if
taskid
not
in
DataStore
.
tasks
:
logger
.
warning
(
"[%s] Invalid task ID provided to scan_start()"
%
taskid
)
return
jsonize
({
"success"
:
False
,
"message"
:
"Invalid task ID"
})
# Initialize sqlmap engine's options with user's provided options, if any
for
option
,
value
in
request
.
json
.
items
():
DataStore
.
tasks
[
taskid
].
set_option
(
option
,
value
)
# Overwrite output directory value to a temporary directory
DataStore
.
tasks
[
taskid
].
set_output_directory
()
# Launch sqlmap engine in a separate process
DataStore
.
tasks
[
taskid
].
engine_start
()
logger
.
debug
(
"[%s] Started scan"
%
taskid
)
return
jsonize
({
"success"
:
True
,
"engineid"
:
DataStore
.
tasks
[
taskid
].
engine_get_id
()})
@
get
(
"/scan/<taskid>/stop"
)
def
scan_stop
(
taskid
):
"""
Stop a scan
"""
if
taskid
not
in
DataStore
.
tasks
:
logger
.
warning
(
"[%s] Invalid task ID provided to scan_stop()"
%
taskid
)
return
jsonize
({
"success"
:
False
,
"message"
:
"Invalid task ID"
})
DataStore
.
tasks
[
taskid
].
engine_stop
()
logger
.
debug
(
"[%s] Stopped scan"
%
taskid
)
return
jsonize
({
"success"
:
True
})
@
get
(
"/scan/<taskid>/kill"
)
def
scan_kill
(
taskid
):
"""
Kill a scan
"""
if
taskid
not
in
DataStore
.
tasks
:
logger
.
warning
(
"[%s] Invalid task ID provided to scan_kill()"
%
taskid
)
return
jsonize
({
"success"
:
False
,
"message"
:
"Invalid task ID"
})
DataStore
.
tasks
[
taskid
].
engine_kill
()
logger
.
debug
(
"[%s] Killed scan"
%
taskid
)
return
jsonize
({
"success"
:
True
})
@
get
(
"/scan/<taskid>/status"
)
def
scan_status
(
taskid
):
"""
Returns status of a scan
"""
if
taskid
not
in
DataStore
.
tasks
:
logger
.
warning
(
"[%s] Invalid task ID provided to scan_status()"
%
taskid
)
return
jsonize
({
"success"
:
False
,
"message"
:
"Invalid task ID"
})
if
DataStore
.
tasks
[
taskid
].
engine_process
()
is
None
:
status
=
"not running"
else
:
status
=
"terminated"
if
DataStore
.
tasks
[
taskid
].
engine_has_terminated
()
is
True
else
"running"
logger
.
debug
(
"[%s] Retrieved scan status"
%
taskid
)
return
jsonize
({
"success"
:
True
,
"status"
:
status
,
"returncode"
:
DataStore
.
tasks
[
taskid
].
engine_get_returncode
()
})
@
get
(
"/scan/<taskid>/data"
)
def
scan_data
(
taskid
):
"""
Retrieve the data of a scan
"""
json_data_message
=
list
()
json_errors_message
=
list
()
if
taskid
not
in
DataStore
.
tasks
:
logger
.
warning
(
"[%s] Invalid task ID provided to scan_data()"
%
taskid
)
return
jsonize
({
"success"
:
False
,
"message"
:
"Invalid task ID"
})
# Read all data from the IPC database for the taskid
for
status
,
content_type
,
value
in
DataStore
.
current_db
.
execute
(
"SELECT status, content_type, value FROM data WHERE taskid = ? ORDER BY id ASC"
,
(
taskid
,)):
json_data_message
.
append
(
{
"status"
:
status
,
"type"
:
content_type
,
"value"
:
dejsonize
(
value
)})
# Read all error messages from the IPC database
for
error
in
DataStore
.
current_db
.
execute
(
"SELECT error FROM errors WHERE taskid = ? ORDER BY id ASC"
,
(
taskid
,)):
json_errors_message
.
append
(
error
)
logger
.
debug
(
"[%s] Retrieved scan data and error messages"
%
taskid
)
return
jsonize
({
"success"
:
True
,
"data"
:
json_data_message
,
"error"
:
json_errors_message
})
# Functions to handle scans' logs
@
get
(
"/scan/<taskid>/log/<start>/<end>"
)
def
scan_log_limited
(
taskid
,
start
,
end
):
"""
Retrieve a subset of log messages
"""
json_log_messages
=
list
()
if
taskid
not
in
DataStore
.
tasks
:
logger
.
warning
(
"[%s] Invalid task ID provided to scan_log_limited()"
)
return
jsonize
({
"success"
:
False
,
"message"
:
"Invalid task ID"
})
if
not
start
.
isdigit
()
or
not
end
.
isdigit
()
or
end
<
start
:
logger
.
warning
(
"[%s] Invalid start or end value provided to scan_log_limited()"
%
taskid
)
return
jsonize
({
"success"
:
False
,
"message"
:
"Invalid start or end value, must be digits"
})
start
=
max
(
1
,
int
(
start
))
end
=
max
(
1
,
int
(
end
))
# Read a subset of log messages from the IPC database
for
time_
,
level
,
message
in
DataStore
.
current_db
.
execute
(
(
"SELECT time, level, message FROM logs WHERE "
"taskid = ? AND id >= ? AND id <= ? ORDER BY id ASC"
),
(
taskid
,
start
,
end
)):
json_log_messages
.
append
({
"time"
:
time_
,
"level"
:
level
,
"message"
:
message
})
logger
.
debug
(
"[%s] Retrieved scan log messages subset"
%
taskid
)
return
jsonize
({
"success"
:
True
,
"log"
:
json_log_messages
})
@
get
(
"/scan/<taskid>/log"
)
def
scan_log
(
taskid
):
"""
Retrieve the log messages
"""
json_log_messages
=
list
()
if
taskid
not
in
DataStore
.
tasks
:
logger
.
warning
(
"[%s] Invalid task ID provided to scan_log()"
)
return
jsonize
({
"success"
:
False
,
"message"
:
"Invalid task ID"
})
# Read all log messages from the IPC database
for
time_
,
level
,
message
in
DataStore
.
current_db
.
execute
(
"SELECT time, level, message FROM logs WHERE taskid = ? ORDER BY id ASC"
, (
taskid
,)):
json_log_messages
.
append
({
"time"
:
time_
,
"level"
:
level
,
"message"
:
message
})
logger
.
debug
(
"[%s] Retrieved scan log messages"
%
taskid
)
return
jsonize
({
"success"
:
True
,
"log"
:
json_log_messages
})
# Function to handle files inside the output directory
@
get
(
"/download/<taskid>/<target>/<filename:path>"
)
def
download
(
taskid
,
target
,
filename
):
"""
Download a certain file from the file system
"""
if
taskid
not
in
DataStore
.
tasks
:
logger
.
warning
(
"[%s] Invalid task ID provided to download()"
%
taskid
)
return
jsonize
({
"success"
:
False
,
"message"
:
"Invalid task ID"
})
# Prevent file path traversal - the lame way
if
".."
in
target
:
logger
.
warning
(
"[%s] Forbidden path (%s)"
%
(
taskid
,
target
))
return
jsonize
({
"success"
:
False
,
"message"
:
"Forbidden path"
})
path
=
os
.
path
.
join
(
paths
.
SQLMAP_OUTPUT_PATH
,
target
)
if
os
.
path
.
exists
(
path
):
logger
.
debug
(
"[%s] Retrieved content of file %s"
%
(
taskid
,
target
))
with
open
(
path
,
'rb'
)
as
inf
:
file_content
=
inf
.
read
()
return
jsonize
({
"success"
:
True
,
"file"
:
file_content
.
encode
(
"base64"
)})
else
:
logger
.
warning
(
"[%s] File does not exist %s"
%
(
taskid
,
target
))
return
jsonize
({
"success"
:
False
,
"message"
:
"File does not exist"
})
def
server
(
host
=
"0.0.0.0"
,
port
=
RESTAPI_SERVER_PORT
):
"""
REST-JSON API server
"""
DataStore
.
admin_id
=
hexencode
(
os
.
urandom
(
16
))
Database
.
filepath
=
tempfile
.
mkstemp
(
prefix
=
"sqlmapipc-"
,
text
=
False
)[
1
]
logger
.
info
(
"Running REST-JSON API server at '%s:%d'.."
%
(
host
,
port
))
logger
.
info
(
"Admin ID: %s"
%
DataStore
.
admin_id
)
logger
.
debug
(
"IPC database: %s"
%
Database
.
filepath
)
# Initialize IPC database
DataStore
.
current_db
=
Database
()
DataStore
.
current_db
.
connect
()
DataStore
.
current_db
.
init
()
# Run RESTful API
run
(
host
=
host
,
port
=
port
,
quiet
=
True
,
debug
=
False
)
def
client
(
host
=
RESTAPI_SERVER_HOST
,
port
=
RESTAPI_SERVER_PORT
):
"""
REST-JSON API client
"""
addr
=
"http://%s:%d"
%
(
host
,
port
)
logger
.
info
(
"Starting REST-JSON API client to '%s'..."
%
addr
)
# TODO: write a simple client with requests, for now use curl from command line
logger
.
error
(
"Not yet implemented, use curl from command line instead for now, for example:"
)
print
"
\n
\t
$ curl http://%s:%d/task/new"
%
(
host
,
port
)
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
)
print
"
\t
$ curl http://%s:%d/scan/:taskid/data"
%
(
host
,
port
)
print
"
\t
$ curl http://%s:%d/scan/:taskid/log
\n
"
%
(
host
,
port
)
Back
|
FazBrowse Home
|
New Git URL