Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sqlmapproject
GitHub Repository: sqlmapproject/sqlmap
Path: blob/master/lib/core/target.py
3553 views
1
#!/usr/bin/env python
2
3
"""
4
Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
5
See the file 'LICENSE' for copying permission
6
"""
7
8
import functools
9
import os
10
import re
11
import subprocess
12
import sys
13
import tempfile
14
import time
15
16
from lib.core.common import Backend
17
from lib.core.common import getSafeExString
18
from lib.core.common import hashDBRetrieve
19
from lib.core.common import intersect
20
from lib.core.common import isNumPosStrValue
21
from lib.core.common import normalizeUnicode
22
from lib.core.common import openFile
23
from lib.core.common import paramToDict
24
from lib.core.common import randomStr
25
from lib.core.common import readInput
26
from lib.core.common import removePostHintPrefix
27
from lib.core.common import resetCookieJar
28
from lib.core.common import safeStringFormat
29
from lib.core.common import unArrayizeValue
30
from lib.core.common import urldecode
31
from lib.core.compat import xrange
32
from lib.core.convert import decodeBase64
33
from lib.core.convert import getUnicode
34
from lib.core.data import conf
35
from lib.core.data import kb
36
from lib.core.data import logger
37
from lib.core.data import mergedOptions
38
from lib.core.data import paths
39
from lib.core.datatype import InjectionDict
40
from lib.core.dicts import DBMS_DICT
41
from lib.core.dump import dumper
42
from lib.core.enums import HASHDB_KEYS
43
from lib.core.enums import HTTP_HEADER
44
from lib.core.enums import HTTPMETHOD
45
from lib.core.enums import MKSTEMP_PREFIX
46
from lib.core.enums import PLACE
47
from lib.core.enums import POST_HINT
48
from lib.core.exception import SqlmapFilePathException
49
from lib.core.exception import SqlmapGenericException
50
from lib.core.exception import SqlmapMissingPrivileges
51
from lib.core.exception import SqlmapNoneDataException
52
from lib.core.exception import SqlmapSystemException
53
from lib.core.exception import SqlmapUserQuitException
54
from lib.core.option import _setAuthCred
55
from lib.core.option import _setDBMS
56
from lib.core.option import _setKnowledgeBaseAttributes
57
from lib.core.settings import ARRAY_LIKE_RECOGNITION_REGEX
58
from lib.core.settings import ASTERISK_MARKER
59
from lib.core.settings import CSRF_TOKEN_PARAMETER_INFIXES
60
from lib.core.settings import CUSTOM_INJECTION_MARK_CHAR
61
from lib.core.settings import DEFAULT_GET_POST_DELIMITER
62
from lib.core.settings import HOST_ALIASES
63
from lib.core.settings import INJECT_HERE_REGEX
64
from lib.core.settings import JSON_LIKE_RECOGNITION_REGEX
65
from lib.core.settings import JSON_RECOGNITION_REGEX
66
from lib.core.settings import MULTIPART_RECOGNITION_REGEX
67
from lib.core.settings import PROBLEMATIC_CUSTOM_INJECTION_PATTERNS
68
from lib.core.settings import REFERER_ALIASES
69
from lib.core.settings import RESTORE_MERGED_OPTIONS
70
from lib.core.settings import RESULTS_FILE_FORMAT
71
from lib.core.settings import SESSION_SQLITE_FILE
72
from lib.core.settings import SUPPORTED_DBMS
73
from lib.core.settings import UNENCODED_ORIGINAL_VALUE
74
from lib.core.settings import UNICODE_ENCODING
75
from lib.core.settings import UNKNOWN_DBMS_VERSION
76
from lib.core.settings import URI_INJECTABLE_REGEX
77
from lib.core.settings import USER_AGENT_ALIASES
78
from lib.core.settings import XML_RECOGNITION_REGEX
79
from lib.core.threads import getCurrentThreadData
80
from lib.utils.hashdb import HashDB
81
from thirdparty import six
82
from thirdparty.odict import OrderedDict
83
from thirdparty.six.moves import urllib as _urllib
84
85
def _setRequestParams():
86
"""
87
Check and set the parameters and perform checks on 'data' option for
88
HTTP method POST.
89
"""
90
91
if conf.direct:
92
conf.parameters[None] = "direct connection"
93
return
94
95
hintNames = []
96
testableParameters = False
97
98
# Perform checks on GET parameters
99
if conf.parameters.get(PLACE.GET):
100
parameters = conf.parameters[PLACE.GET]
101
paramDict = paramToDict(PLACE.GET, parameters)
102
103
if paramDict:
104
conf.paramDict[PLACE.GET] = paramDict
105
testableParameters = True
106
107
# Perform checks on POST parameters
108
if conf.method == HTTPMETHOD.POST and conf.data is None:
109
logger.warning("detected empty POST body")
110
conf.data = ""
111
112
if conf.data is not None:
113
conf.method = conf.method or HTTPMETHOD.POST
114
115
def process(match, repl):
116
retVal = match.group(0)
117
118
if not (conf.testParameter and match.group("name") not in (removePostHintPrefix(_) for _ in conf.testParameter)) and match.group("name") == match.group("name").strip('\\'):
119
retVal = repl
120
while True:
121
_ = re.search(r"\\g<([^>]+)>", retVal)
122
if _:
123
try:
124
retVal = retVal.replace(_.group(0), match.group(int(_.group(1)) if _.group(1).isdigit() else _.group(1)))
125
except IndexError:
126
break
127
else:
128
break
129
if kb.customInjectionMark in retVal:
130
hintNames.append((retVal.split(kb.customInjectionMark)[0], match.group("name").strip('"\'') if kb.postHint == POST_HINT.JSON_LIKE else match.group("name")))
131
132
return retVal
133
134
if kb.processUserMarks is None and kb.customInjectionMark in conf.data:
135
message = "custom injection marker ('%s') found in %s " % (kb.customInjectionMark, conf.method)
136
message += "body. Do you want to process it? [Y/n/q] "
137
choice = readInput(message, default='Y').upper()
138
139
if choice == 'Q':
140
raise SqlmapUserQuitException
141
else:
142
kb.processUserMarks = choice == 'Y'
143
144
if kb.processUserMarks:
145
kb.testOnlyCustom = True
146
147
if re.search(JSON_RECOGNITION_REGEX, conf.data):
148
message = "JSON data found in %s body. " % conf.method
149
message += "Do you want to process it? [Y/n/q] "
150
choice = readInput(message, default='Y').upper()
151
152
if choice == 'Q':
153
raise SqlmapUserQuitException
154
elif choice == 'Y':
155
kb.postHint = POST_HINT.JSON
156
if not (kb.processUserMarks and kb.customInjectionMark in conf.data):
157
conf.data = getattr(conf.data, UNENCODED_ORIGINAL_VALUE, conf.data)
158
conf.data = conf.data.replace(kb.customInjectionMark, ASTERISK_MARKER)
159
conf.data = re.sub(r'("(?P<name>[^"]+)"\s*:\s*".*?)"(?<!\\")', functools.partial(process, repl=r'\g<1>%s"' % kb.customInjectionMark), conf.data)
160
conf.data = re.sub(r'("(?P<name>[^"]+)"\s*:\s*")"', functools.partial(process, repl=r'\g<1>%s"' % kb.customInjectionMark), conf.data)
161
conf.data = re.sub(r'("(?P<name>[^"]+)"\s*:\s*)(-?\d[\d\.]*)\b', functools.partial(process, repl=r'\g<1>\g<3>%s' % kb.customInjectionMark), conf.data)
162
conf.data = re.sub(r'("(?P<name>[^"]+)"\s*:\s*)((true|false|null))\b', functools.partial(process, repl=r'\g<1>\g<3>%s' % kb.customInjectionMark), conf.data)
163
for match in re.finditer(r'(?P<name>[^"]+)"\s*:\s*\[([^\]]+)\]', conf.data):
164
if not (conf.testParameter and match.group("name") not in conf.testParameter):
165
_ = match.group(2)
166
if kb.customInjectionMark not in _: # Note: only for unprocessed (simple) forms - i.e. non-associative arrays (e.g. [1,2,3])
167
_ = re.sub(r'("[^"]+)"', r'\g<1>%s"' % kb.customInjectionMark, _)
168
_ = re.sub(r'(\A|,|\s+)(-?\d[\d\.]*\b)', r'\g<0>%s' % kb.customInjectionMark, _)
169
conf.data = conf.data.replace(match.group(0), match.group(0).replace(match.group(2), _))
170
171
elif re.search(JSON_LIKE_RECOGNITION_REGEX, conf.data):
172
message = "JSON-like data found in %s body. " % conf.method
173
message += "Do you want to process it? [Y/n/q] "
174
choice = readInput(message, default='Y').upper()
175
176
if choice == 'Q':
177
raise SqlmapUserQuitException
178
elif choice == 'Y':
179
kb.postHint = POST_HINT.JSON_LIKE
180
if not (kb.processUserMarks and kb.customInjectionMark in conf.data):
181
conf.data = getattr(conf.data, UNENCODED_ORIGINAL_VALUE, conf.data)
182
conf.data = conf.data.replace(kb.customInjectionMark, ASTERISK_MARKER)
183
if '"' in conf.data:
184
conf.data = re.sub(r'((?P<name>"[^"]+"|\w+)\s*:\s*"[^"]+)"', functools.partial(process, repl=r'\g<1>%s"' % kb.customInjectionMark), conf.data)
185
conf.data = re.sub(r'((?P<name>"[^"]+"|\w+)\s*:\s*)(-?\d[\d\.]*\b)', functools.partial(process, repl=r'\g<0>%s' % kb.customInjectionMark), conf.data)
186
else:
187
conf.data = re.sub(r"((?P<name>'[^']+'|\w+)\s*:\s*'[^']+)'", functools.partial(process, repl=r"\g<1>%s'" % kb.customInjectionMark), conf.data)
188
conf.data = re.sub(r"((?P<name>'[^']+'|\w+)\s*:\s*)(-?\d[\d\.]*\b)", functools.partial(process, repl=r"\g<0>%s" % kb.customInjectionMark), conf.data)
189
190
elif re.search(ARRAY_LIKE_RECOGNITION_REGEX, conf.data):
191
message = "Array-like data found in %s body. " % conf.method
192
message += "Do you want to process it? [Y/n/q] "
193
choice = readInput(message, default='Y').upper()
194
195
if choice == 'Q':
196
raise SqlmapUserQuitException
197
elif choice == 'Y':
198
kb.postHint = POST_HINT.ARRAY_LIKE
199
if not (kb.processUserMarks and kb.customInjectionMark in conf.data):
200
conf.data = conf.data.replace(kb.customInjectionMark, ASTERISK_MARKER)
201
conf.data = re.sub(r"(=[^%s]+)" % DEFAULT_GET_POST_DELIMITER, r"\g<1>%s" % kb.customInjectionMark, conf.data)
202
203
elif re.search(XML_RECOGNITION_REGEX, conf.data):
204
message = "SOAP/XML data found in %s body. " % conf.method
205
message += "Do you want to process it? [Y/n/q] "
206
choice = readInput(message, default='Y').upper()
207
208
if choice == 'Q':
209
raise SqlmapUserQuitException
210
elif choice == 'Y':
211
kb.postHint = POST_HINT.SOAP if "soap" in conf.data.lower() else POST_HINT.XML
212
if not (kb.processUserMarks and kb.customInjectionMark in conf.data):
213
conf.data = getattr(conf.data, UNENCODED_ORIGINAL_VALUE, conf.data)
214
conf.data = conf.data.replace(kb.customInjectionMark, ASTERISK_MARKER)
215
conf.data = re.sub(r"(<(?P<name>[^>]+)( [^<]*)?>)([^<]+)(</\2)", functools.partial(process, repl=r"\g<1>\g<4>%s\g<5>" % kb.customInjectionMark), conf.data)
216
217
elif re.search(MULTIPART_RECOGNITION_REGEX, conf.data):
218
message = "Multipart-like data found in %s body. " % conf.method
219
message += "Do you want to process it? [Y/n/q] "
220
choice = readInput(message, default='Y').upper()
221
222
if choice == 'Q':
223
raise SqlmapUserQuitException
224
elif choice == 'Y':
225
kb.postHint = POST_HINT.MULTIPART
226
if not (kb.processUserMarks and kb.customInjectionMark in conf.data):
227
conf.data = getattr(conf.data, UNENCODED_ORIGINAL_VALUE, conf.data)
228
conf.data = conf.data.replace(kb.customInjectionMark, ASTERISK_MARKER)
229
conf.data = re.sub(r"(?si)(Content-Disposition:[^\n]+\s+name=\"(?P<name>[^\"]+)\"(?:[^f|^b]|f(?!ilename=)|b(?!oundary=))*?)((%s)--)" % ("\r\n" if "\r\n" in conf.data else '\n'),
230
functools.partial(process, repl=r"\g<1>%s\g<3>" % kb.customInjectionMark), conf.data)
231
232
if not kb.postHint:
233
if kb.customInjectionMark in conf.data: # later processed
234
pass
235
else:
236
place = PLACE.POST
237
238
conf.parameters[place] = conf.data
239
paramDict = paramToDict(place, conf.data)
240
241
if paramDict:
242
conf.paramDict[place] = paramDict
243
testableParameters = True
244
else:
245
if kb.customInjectionMark not in conf.data: # in case that no usable parameter values has been found
246
conf.parameters[PLACE.POST] = conf.data
247
248
kb.processUserMarks = True if (kb.postHint and kb.customInjectionMark in (conf.data or "")) else kb.processUserMarks
249
250
if re.search(URI_INJECTABLE_REGEX, conf.url, re.I) and not any(place in conf.parameters for place in (PLACE.GET, PLACE.POST)) and not kb.postHint and kb.customInjectionMark not in (conf.data or "") and conf.url.startswith("http"):
251
warnMsg = "you've provided target URL without any GET "
252
warnMsg += "parameters (e.g. 'http://www.site.com/article.php?id=1') "
253
warnMsg += "and without providing any POST parameters "
254
warnMsg += "through option '--data'"
255
logger.warning(warnMsg)
256
257
message = "do you want to try URI injections "
258
message += "in the target URL itself? [Y/n/q] "
259
choice = readInput(message, default='Y').upper()
260
261
if choice == 'Q':
262
raise SqlmapUserQuitException
263
elif choice == 'Y':
264
conf.url = "%s%s" % (conf.url, kb.customInjectionMark)
265
kb.processUserMarks = True
266
267
for place, value in ((PLACE.URI, conf.url), (PLACE.CUSTOM_POST, conf.data), (PLACE.CUSTOM_HEADER, str(conf.httpHeaders))):
268
if place == PLACE.CUSTOM_HEADER and any((conf.forms, conf.crawlDepth)):
269
continue
270
271
_ = re.sub(PROBLEMATIC_CUSTOM_INJECTION_PATTERNS, "", value or "") if place == PLACE.CUSTOM_HEADER else value or ""
272
if kb.customInjectionMark in _:
273
if kb.processUserMarks is None:
274
lut = {PLACE.URI: '-u', PLACE.CUSTOM_POST: '--data', PLACE.CUSTOM_HEADER: '--headers/--user-agent/--referer/--cookie'}
275
message = "custom injection marker ('%s') found in option " % kb.customInjectionMark
276
message += "'%s'. Do you want to process it? [Y/n/q] " % lut[place]
277
choice = readInput(message, default='Y').upper()
278
279
if choice == 'Q':
280
raise SqlmapUserQuitException
281
else:
282
kb.processUserMarks = choice == 'Y'
283
284
if kb.processUserMarks:
285
kb.testOnlyCustom = True
286
287
if "=%s" % kb.customInjectionMark in _:
288
warnMsg = "it seems that you've provided empty parameter value(s) "
289
warnMsg += "for testing. Please, always use only valid parameter values "
290
warnMsg += "so sqlmap could be able to run properly"
291
logger.warning(warnMsg)
292
293
if not kb.processUserMarks:
294
if place == PLACE.URI:
295
query = _urllib.parse.urlsplit(value).query
296
if query:
297
parameters = conf.parameters[PLACE.GET] = query
298
paramDict = paramToDict(PLACE.GET, parameters)
299
300
if paramDict:
301
conf.url = conf.url.split('?')[0]
302
conf.paramDict[PLACE.GET] = paramDict
303
testableParameters = True
304
elif place == PLACE.CUSTOM_POST:
305
conf.parameters[PLACE.POST] = conf.data
306
paramDict = paramToDict(PLACE.POST, conf.data)
307
308
if paramDict:
309
conf.paramDict[PLACE.POST] = paramDict
310
testableParameters = True
311
312
else:
313
if place == PLACE.URI:
314
value = conf.url = conf.url.replace('+', "%20") # NOTE: https://github.com/sqlmapproject/sqlmap/issues/5123
315
316
conf.parameters[place] = value
317
conf.paramDict[place] = OrderedDict()
318
319
if place == PLACE.CUSTOM_HEADER:
320
for index in xrange(len(conf.httpHeaders)):
321
header, value = conf.httpHeaders[index]
322
if kb.customInjectionMark in re.sub(PROBLEMATIC_CUSTOM_INJECTION_PATTERNS, "", value):
323
parts = value.split(kb.customInjectionMark)
324
for i in xrange(len(parts) - 1):
325
conf.paramDict[place]["%s #%d%s" % (header, i + 1, kb.customInjectionMark)] = "%s,%s" % (header, "".join("%s%s" % (parts[j], kb.customInjectionMark if i == j else "") for j in xrange(len(parts))))
326
conf.httpHeaders[index] = (header, value.replace(kb.customInjectionMark, ""))
327
else:
328
parts = value.split(kb.customInjectionMark)
329
330
for i in xrange(len(parts) - 1):
331
name = None
332
if kb.postHint:
333
for ending, _ in hintNames:
334
if parts[i].endswith(ending):
335
name = "%s %s" % (kb.postHint, _)
336
break
337
if name is None:
338
name = "%s#%s%s" % (("%s " % kb.postHint) if kb.postHint else "", i + 1, kb.customInjectionMark)
339
conf.paramDict[place][name] = "".join("%s%s" % (parts[j], kb.customInjectionMark if i == j else "") for j in xrange(len(parts)))
340
341
if place == PLACE.URI and PLACE.GET in conf.paramDict:
342
del conf.paramDict[PLACE.GET]
343
elif place == PLACE.CUSTOM_POST and PLACE.POST in conf.paramDict:
344
del conf.paramDict[PLACE.POST]
345
346
testableParameters = True
347
348
if kb.processUserMarks:
349
for item in ("url", "data", "agent", "referer", "cookie"):
350
if conf.get(item):
351
conf[item] = conf[item].replace(kb.customInjectionMark, "")
352
353
# Perform checks on Cookie parameters
354
if conf.cookie:
355
conf.parameters[PLACE.COOKIE] = conf.cookie
356
paramDict = paramToDict(PLACE.COOKIE, conf.cookie)
357
358
if paramDict:
359
conf.paramDict[PLACE.COOKIE] = paramDict
360
testableParameters = True
361
362
# Perform checks on header values
363
if conf.httpHeaders:
364
for httpHeader, headerValue in list(conf.httpHeaders):
365
# Url encoding of the header values should be avoided
366
# Reference: http://stackoverflow.com/questions/5085904/is-ok-to-urlencode-the-value-in-headerlocation-value
367
368
if httpHeader.upper() == HTTP_HEADER.USER_AGENT.upper():
369
conf.parameters[PLACE.USER_AGENT] = urldecode(headerValue)
370
371
condition = any((not conf.testParameter, intersect(conf.testParameter, USER_AGENT_ALIASES, True)))
372
373
if condition:
374
conf.paramDict[PLACE.USER_AGENT] = {PLACE.USER_AGENT: headerValue}
375
testableParameters = True
376
377
elif httpHeader.upper() == HTTP_HEADER.REFERER.upper():
378
conf.parameters[PLACE.REFERER] = urldecode(headerValue)
379
380
condition = any((not conf.testParameter, intersect(conf.testParameter, REFERER_ALIASES, True)))
381
382
if condition:
383
conf.paramDict[PLACE.REFERER] = {PLACE.REFERER: headerValue}
384
testableParameters = True
385
386
elif httpHeader.upper() == HTTP_HEADER.HOST.upper():
387
conf.parameters[PLACE.HOST] = urldecode(headerValue)
388
389
condition = any((not conf.testParameter, intersect(conf.testParameter, HOST_ALIASES, True)))
390
391
if condition:
392
conf.paramDict[PLACE.HOST] = {PLACE.HOST: headerValue}
393
testableParameters = True
394
395
else:
396
condition = intersect(conf.testParameter, [httpHeader], True)
397
398
if condition:
399
conf.parameters[PLACE.CUSTOM_HEADER] = str(conf.httpHeaders)
400
conf.paramDict[PLACE.CUSTOM_HEADER] = {httpHeader: "%s,%s%s" % (httpHeader, headerValue, kb.customInjectionMark)}
401
conf.httpHeaders = [(_[0], _[1].replace(kb.customInjectionMark, "")) for _ in conf.httpHeaders]
402
testableParameters = True
403
404
if not conf.parameters:
405
errMsg = "you did not provide any GET, POST and Cookie "
406
errMsg += "parameter, neither an User-Agent, Referer or Host header value"
407
raise SqlmapGenericException(errMsg)
408
409
elif not testableParameters:
410
errMsg = "all testable parameters you provided are not present "
411
errMsg += "within the given request data"
412
raise SqlmapGenericException(errMsg)
413
414
if conf.csrfToken:
415
if not any(re.search(conf.csrfToken, ' '.join(_), re.I) for _ in (conf.paramDict.get(PLACE.GET, {}), conf.paramDict.get(PLACE.POST, {}), conf.paramDict.get(PLACE.COOKIE, {}))) and not re.search(r"\b%s\b" % conf.csrfToken, conf.data or "") and conf.csrfToken not in set(_[0].lower() for _ in conf.httpHeaders) and conf.csrfToken not in conf.paramDict.get(PLACE.COOKIE, {}) and not all(re.search(conf.csrfToken, _, re.I) for _ in conf.paramDict.get(PLACE.URI, {}).values()):
416
errMsg = "anti-CSRF token parameter '%s' not " % conf.csrfToken._original
417
errMsg += "found in provided GET, POST, Cookie or header values"
418
raise SqlmapGenericException(errMsg)
419
else:
420
for place in (PLACE.GET, PLACE.POST, PLACE.COOKIE):
421
if conf.csrfToken:
422
break
423
424
for parameter in conf.paramDict.get(place, {}):
425
if any(parameter.lower().count(_) for _ in CSRF_TOKEN_PARAMETER_INFIXES):
426
message = "%sparameter '%s' appears to hold anti-CSRF token. " % ("%s " % place if place != parameter else "", parameter)
427
message += "Do you want sqlmap to automatically update it in further requests? [y/N] "
428
429
if readInput(message, default='N', boolean=True):
430
class _(six.text_type):
431
pass
432
conf.csrfToken = _(re.escape(getUnicode(parameter)))
433
conf.csrfToken._original = getUnicode(parameter)
434
break
435
436
def _setHashDB():
437
"""
438
Check and set the HashDB SQLite file for query resume functionality.
439
"""
440
441
if not conf.hashDBFile:
442
conf.hashDBFile = conf.sessionFile or os.path.join(conf.outputPath, SESSION_SQLITE_FILE)
443
444
if conf.flushSession:
445
if os.path.exists(conf.hashDBFile):
446
if conf.hashDB:
447
conf.hashDB.closeAll()
448
449
try:
450
os.remove(conf.hashDBFile)
451
logger.info("flushing session file")
452
except OSError as ex:
453
errMsg = "unable to flush the session file ('%s')" % getSafeExString(ex)
454
raise SqlmapFilePathException(errMsg)
455
456
for suffix in ("-shm", "-wal"):
457
leftover = conf.hashDBFile + suffix
458
if os.path.exists(leftover):
459
try:
460
os.remove(leftover)
461
except OSError:
462
pass
463
464
conf.hashDB = HashDB(conf.hashDBFile)
465
466
def _resumeHashDBValues():
467
"""
468
Resume stored data values from HashDB
469
"""
470
471
kb.absFilePaths = hashDBRetrieve(HASHDB_KEYS.KB_ABS_FILE_PATHS, True) or kb.absFilePaths
472
kb.brute.tables = hashDBRetrieve(HASHDB_KEYS.KB_BRUTE_TABLES, True) or kb.brute.tables
473
kb.brute.columns = hashDBRetrieve(HASHDB_KEYS.KB_BRUTE_COLUMNS, True) or kb.brute.columns
474
kb.chars = hashDBRetrieve(HASHDB_KEYS.KB_CHARS, True) or kb.chars
475
kb.dynamicMarkings = hashDBRetrieve(HASHDB_KEYS.KB_DYNAMIC_MARKINGS, True) or kb.dynamicMarkings
476
kb.xpCmdshellAvailable = hashDBRetrieve(HASHDB_KEYS.KB_XP_CMDSHELL_AVAILABLE) or kb.xpCmdshellAvailable
477
478
kb.errorChunkLength = hashDBRetrieve(HASHDB_KEYS.KB_ERROR_CHUNK_LENGTH)
479
if isNumPosStrValue(kb.errorChunkLength):
480
kb.errorChunkLength = int(kb.errorChunkLength)
481
else:
482
kb.errorChunkLength = None
483
484
conf.tmpPath = conf.tmpPath or hashDBRetrieve(HASHDB_KEYS.CONF_TMP_PATH)
485
486
for injection in hashDBRetrieve(HASHDB_KEYS.KB_INJECTIONS, True) or []:
487
if isinstance(injection, InjectionDict) and injection.place in conf.paramDict and injection.parameter in conf.paramDict[injection.place]:
488
if not conf.technique or intersect(conf.technique, injection.data.keys()):
489
if intersect(conf.technique, injection.data.keys()):
490
injection.data = dict(_ for _ in injection.data.items() if _[0] in conf.technique)
491
if injection not in kb.injections:
492
kb.injections.append(injection)
493
kb.vulnHosts.add(conf.hostname)
494
495
_resumeDBMS()
496
_resumeOS()
497
498
def _resumeDBMS():
499
"""
500
Resume stored DBMS information from HashDB
501
"""
502
503
value = hashDBRetrieve(HASHDB_KEYS.DBMS)
504
505
if not value:
506
if conf.offline:
507
errMsg = "unable to continue in offline mode "
508
errMsg += "because of lack of usable "
509
errMsg += "session data"
510
raise SqlmapNoneDataException(errMsg)
511
else:
512
return
513
514
dbms = value.lower()
515
dbmsVersion = [UNKNOWN_DBMS_VERSION]
516
_ = "(%s)" % ('|'.join(SUPPORTED_DBMS))
517
_ = re.search(r"\A%s (.*)" % _, dbms, re.I)
518
519
if _:
520
dbms = _.group(1).lower()
521
dbmsVersion = [_.group(2)]
522
523
if conf.dbms:
524
check = True
525
for aliases, _, _, _ in DBMS_DICT.values():
526
if conf.dbms.lower() in aliases and dbms not in aliases:
527
check = False
528
break
529
530
if not check:
531
message = "you provided '%s' as a back-end DBMS, " % conf.dbms
532
message += "but from a past scan information on the target URL "
533
message += "sqlmap assumes the back-end DBMS is '%s'. " % dbms
534
message += "Do you really want to force the back-end "
535
message += "DBMS value? [y/N] "
536
537
if not readInput(message, default='N', boolean=True):
538
conf.dbms = None
539
Backend.setDbms(dbms)
540
Backend.setVersionList(dbmsVersion)
541
else:
542
infoMsg = "resuming back-end DBMS '%s' " % dbms
543
logger.info(infoMsg)
544
545
Backend.setDbms(dbms)
546
Backend.setVersionList(dbmsVersion)
547
548
def _resumeOS():
549
"""
550
Resume stored OS information from HashDB
551
"""
552
553
value = hashDBRetrieve(HASHDB_KEYS.OS)
554
555
if not value:
556
return
557
558
os = value
559
560
if os and os != 'None':
561
infoMsg = "resuming back-end DBMS operating system '%s' " % os
562
logger.info(infoMsg)
563
564
if conf.os and conf.os.lower() != os.lower():
565
message = "you provided '%s' as back-end DBMS operating " % conf.os
566
message += "system, but from a past scan information on the "
567
message += "target URL sqlmap assumes the back-end DBMS "
568
message += "operating system is %s. " % os
569
message += "Do you really want to force the back-end DBMS "
570
message += "OS value? [y/N] "
571
572
if not readInput(message, default='N', boolean=True):
573
conf.os = os
574
else:
575
conf.os = os
576
577
Backend.setOs(conf.os)
578
579
def _setResultsFile():
580
"""
581
Create results file for storing results of running in a
582
multiple target mode.
583
"""
584
585
if not conf.multipleTargets:
586
return
587
588
if not conf.resultsFP:
589
conf.resultsFile = conf.resultsFile or os.path.join(paths.SQLMAP_OUTPUT_PATH, time.strftime(RESULTS_FILE_FORMAT).lower())
590
found = os.path.exists(conf.resultsFile)
591
592
try:
593
conf.resultsFP = openFile(conf.resultsFile, "a", UNICODE_ENCODING, buffering=0)
594
except (OSError, IOError) as ex:
595
try:
596
warnMsg = "unable to create results file '%s' ('%s'). " % (conf.resultsFile, getUnicode(ex))
597
handle, conf.resultsFile = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.RESULTS, suffix=".csv")
598
os.close(handle)
599
conf.resultsFP = openFile(conf.resultsFile, "w+", UNICODE_ENCODING, buffering=0)
600
warnMsg += "Using temporary file '%s' instead" % conf.resultsFile
601
logger.warning(warnMsg)
602
except IOError as _:
603
errMsg = "unable to write to the temporary directory ('%s'). " % _
604
errMsg += "Please make sure that your disk is not full and "
605
errMsg += "that you have sufficient write permissions to "
606
errMsg += "create temporary files and/or directories"
607
raise SqlmapSystemException(errMsg)
608
609
if not found:
610
conf.resultsFP.writelines("Target URL,Place,Parameter,Technique(s),Note(s)%s" % os.linesep)
611
612
logger.info("using '%s' as the CSV results file in multiple targets mode" % conf.resultsFile)
613
614
def _createFilesDir():
615
"""
616
Create the file directory.
617
"""
618
619
if not any((conf.fileRead, conf.commonFiles)):
620
return
621
622
conf.filePath = paths.SQLMAP_FILES_PATH % conf.hostname
623
624
if not os.path.isdir(conf.filePath):
625
try:
626
os.makedirs(conf.filePath)
627
except OSError as ex:
628
tempDir = tempfile.mkdtemp(prefix="sqlmapfiles")
629
warnMsg = "unable to create files directory "
630
warnMsg += "'%s' (%s). " % (conf.filePath, getUnicode(ex))
631
warnMsg += "Using temporary directory '%s' instead" % getUnicode(tempDir)
632
logger.warning(warnMsg)
633
634
conf.filePath = tempDir
635
636
def _createDumpDir():
637
"""
638
Create the dump directory.
639
"""
640
641
if not conf.dumpTable and not conf.dumpAll and not conf.search:
642
return
643
644
conf.dumpPath = safeStringFormat(paths.SQLMAP_DUMP_PATH, conf.hostname)
645
646
if not os.path.isdir(conf.dumpPath):
647
try:
648
os.makedirs(conf.dumpPath)
649
except Exception as ex:
650
tempDir = tempfile.mkdtemp(prefix="sqlmapdump")
651
warnMsg = "unable to create dump directory "
652
warnMsg += "'%s' (%s). " % (conf.dumpPath, getUnicode(ex))
653
warnMsg += "Using temporary directory '%s' instead" % getUnicode(tempDir)
654
logger.warning(warnMsg)
655
656
conf.dumpPath = tempDir
657
658
def _configureDumper():
659
conf.dumper = dumper
660
conf.dumper.setOutputFile()
661
662
def _createTargetDirs():
663
"""
664
Create the output directory.
665
"""
666
667
conf.outputPath = os.path.join(getUnicode(paths.SQLMAP_OUTPUT_PATH), normalizeUnicode(getUnicode(conf.hostname)))
668
669
try:
670
if not os.path.isdir(conf.outputPath):
671
os.makedirs(conf.outputPath)
672
except (OSError, IOError, TypeError) as ex:
673
tempDir = tempfile.mkdtemp(prefix="sqlmapoutput")
674
warnMsg = "unable to create output directory "
675
warnMsg += "'%s' (%s). " % (conf.outputPath, getUnicode(ex))
676
warnMsg += "Using temporary directory '%s' instead" % getUnicode(tempDir)
677
logger.warning(warnMsg)
678
679
conf.outputPath = tempDir
680
681
conf.outputPath = getUnicode(conf.outputPath)
682
683
try:
684
with openFile(os.path.join(conf.outputPath, "target.txt"), "w+") as f:
685
f.write(getUnicode(kb.originalUrls.get(conf.url) or conf.url or conf.hostname))
686
f.write(" (%s)" % (HTTPMETHOD.POST if conf.data else HTTPMETHOD.GET))
687
f.write(" # %s" % getUnicode(subprocess.list2cmdline(sys.argv), encoding=sys.stdin.encoding))
688
if conf.data:
689
f.write("\n\n%s" % getUnicode(conf.data))
690
except IOError as ex:
691
if "denied" in getUnicode(ex):
692
errMsg = "you don't have enough permissions "
693
else:
694
errMsg = "something went wrong while trying "
695
errMsg += "to write to the output directory '%s' (%s)" % (paths.SQLMAP_OUTPUT_PATH, getSafeExString(ex))
696
697
raise SqlmapMissingPrivileges(errMsg)
698
except UnicodeError as ex:
699
warnMsg = "something went wrong while saving target data ('%s')" % getSafeExString(ex)
700
logger.warning(warnMsg)
701
702
_createDumpDir()
703
_createFilesDir()
704
_configureDumper()
705
706
def _setAuxOptions():
707
"""
708
Setup auxiliary (host-dependent) options
709
"""
710
711
kb.aliasName = randomStr(seed=hash(conf.hostname or ""))
712
713
def _restoreMergedOptions():
714
"""
715
Restore merged options (command line, configuration file and default values)
716
that could be possibly changed during the testing of previous target.
717
"""
718
719
for option in RESTORE_MERGED_OPTIONS:
720
conf[option] = mergedOptions[option]
721
722
def initTargetEnv():
723
"""
724
Initialize target environment.
725
"""
726
727
if conf.multipleTargets:
728
if conf.hashDB:
729
conf.hashDB.close()
730
731
if conf.cj:
732
resetCookieJar(conf.cj)
733
734
threadData = getCurrentThreadData()
735
threadData.reset()
736
737
conf.paramDict = {}
738
conf.parameters = {}
739
conf.hashDBFile = None
740
741
_setKnowledgeBaseAttributes(False)
742
_restoreMergedOptions()
743
_setDBMS()
744
745
if conf.data:
746
class _(six.text_type):
747
pass
748
749
kb.postUrlEncode = True
750
751
for key, value in conf.httpHeaders:
752
if key.upper() == HTTP_HEADER.CONTENT_TYPE.upper():
753
kb.postUrlEncode = "urlencoded" in value
754
break
755
756
if kb.postUrlEncode:
757
original = conf.data
758
conf.data = _(urldecode(conf.data))
759
setattr(conf.data, UNENCODED_ORIGINAL_VALUE, original)
760
kb.postSpaceToPlus = '+' in original
761
762
if conf.data and unArrayizeValue(conf.base64Parameter) == HTTPMETHOD.POST:
763
if '=' not in conf.data.strip('='):
764
try:
765
original = conf.data
766
conf.data = _(decodeBase64(conf.data, binary=False))
767
setattr(conf.data, UNENCODED_ORIGINAL_VALUE, original)
768
except:
769
pass
770
771
match = re.search(INJECT_HERE_REGEX, "%s %s %s" % (conf.url, conf.data, conf.httpHeaders))
772
kb.customInjectionMark = match.group(0) if match else CUSTOM_INJECTION_MARK_CHAR
773
774
def setupTargetEnv():
775
_createTargetDirs()
776
_setRequestParams()
777
_setHashDB()
778
_resumeHashDBValues()
779
_setResultsFile()
780
_setAuthCred()
781
_setAuxOptions()
782
783