Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sqlmapproject
GitHub Repository: sqlmapproject/sqlmap
Path: blob/master/lib/core/target.py
2989 views
1
#!/usr/bin/env python
2
3
"""
4
Copyright (c) 2006-2025 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
conf.hashDB = HashDB(conf.hashDBFile)
457
458
def _resumeHashDBValues():
459
"""
460
Resume stored data values from HashDB
461
"""
462
463
kb.absFilePaths = hashDBRetrieve(HASHDB_KEYS.KB_ABS_FILE_PATHS, True) or kb.absFilePaths
464
kb.brute.tables = hashDBRetrieve(HASHDB_KEYS.KB_BRUTE_TABLES, True) or kb.brute.tables
465
kb.brute.columns = hashDBRetrieve(HASHDB_KEYS.KB_BRUTE_COLUMNS, True) or kb.brute.columns
466
kb.chars = hashDBRetrieve(HASHDB_KEYS.KB_CHARS, True) or kb.chars
467
kb.dynamicMarkings = hashDBRetrieve(HASHDB_KEYS.KB_DYNAMIC_MARKINGS, True) or kb.dynamicMarkings
468
kb.xpCmdshellAvailable = hashDBRetrieve(HASHDB_KEYS.KB_XP_CMDSHELL_AVAILABLE) or kb.xpCmdshellAvailable
469
470
kb.errorChunkLength = hashDBRetrieve(HASHDB_KEYS.KB_ERROR_CHUNK_LENGTH)
471
if isNumPosStrValue(kb.errorChunkLength):
472
kb.errorChunkLength = int(kb.errorChunkLength)
473
else:
474
kb.errorChunkLength = None
475
476
conf.tmpPath = conf.tmpPath or hashDBRetrieve(HASHDB_KEYS.CONF_TMP_PATH)
477
478
for injection in hashDBRetrieve(HASHDB_KEYS.KB_INJECTIONS, True) or []:
479
if isinstance(injection, InjectionDict) and injection.place in conf.paramDict and injection.parameter in conf.paramDict[injection.place]:
480
if not conf.technique or intersect(conf.technique, injection.data.keys()):
481
if intersect(conf.technique, injection.data.keys()):
482
injection.data = dict(_ for _ in injection.data.items() if _[0] in conf.technique)
483
if injection not in kb.injections:
484
kb.injections.append(injection)
485
kb.vulnHosts.add(conf.hostname)
486
487
_resumeDBMS()
488
_resumeOS()
489
490
def _resumeDBMS():
491
"""
492
Resume stored DBMS information from HashDB
493
"""
494
495
value = hashDBRetrieve(HASHDB_KEYS.DBMS)
496
497
if not value:
498
if conf.offline:
499
errMsg = "unable to continue in offline mode "
500
errMsg += "because of lack of usable "
501
errMsg += "session data"
502
raise SqlmapNoneDataException(errMsg)
503
else:
504
return
505
506
dbms = value.lower()
507
dbmsVersion = [UNKNOWN_DBMS_VERSION]
508
_ = "(%s)" % ('|'.join(SUPPORTED_DBMS))
509
_ = re.search(r"\A%s (.*)" % _, dbms, re.I)
510
511
if _:
512
dbms = _.group(1).lower()
513
dbmsVersion = [_.group(2)]
514
515
if conf.dbms:
516
check = True
517
for aliases, _, _, _ in DBMS_DICT.values():
518
if conf.dbms.lower() in aliases and dbms not in aliases:
519
check = False
520
break
521
522
if not check:
523
message = "you provided '%s' as a back-end DBMS, " % conf.dbms
524
message += "but from a past scan information on the target URL "
525
message += "sqlmap assumes the back-end DBMS is '%s'. " % dbms
526
message += "Do you really want to force the back-end "
527
message += "DBMS value? [y/N] "
528
529
if not readInput(message, default='N', boolean=True):
530
conf.dbms = None
531
Backend.setDbms(dbms)
532
Backend.setVersionList(dbmsVersion)
533
else:
534
infoMsg = "resuming back-end DBMS '%s' " % dbms
535
logger.info(infoMsg)
536
537
Backend.setDbms(dbms)
538
Backend.setVersionList(dbmsVersion)
539
540
def _resumeOS():
541
"""
542
Resume stored OS information from HashDB
543
"""
544
545
value = hashDBRetrieve(HASHDB_KEYS.OS)
546
547
if not value:
548
return
549
550
os = value
551
552
if os and os != 'None':
553
infoMsg = "resuming back-end DBMS operating system '%s' " % os
554
logger.info(infoMsg)
555
556
if conf.os and conf.os.lower() != os.lower():
557
message = "you provided '%s' as back-end DBMS operating " % conf.os
558
message += "system, but from a past scan information on the "
559
message += "target URL sqlmap assumes the back-end DBMS "
560
message += "operating system is %s. " % os
561
message += "Do you really want to force the back-end DBMS "
562
message += "OS value? [y/N] "
563
564
if not readInput(message, default='N', boolean=True):
565
conf.os = os
566
else:
567
conf.os = os
568
569
Backend.setOs(conf.os)
570
571
def _setResultsFile():
572
"""
573
Create results file for storing results of running in a
574
multiple target mode.
575
"""
576
577
if not conf.multipleTargets:
578
return
579
580
if not conf.resultsFP:
581
conf.resultsFile = conf.resultsFile or os.path.join(paths.SQLMAP_OUTPUT_PATH, time.strftime(RESULTS_FILE_FORMAT).lower())
582
found = os.path.exists(conf.resultsFile)
583
584
try:
585
conf.resultsFP = openFile(conf.resultsFile, "a", UNICODE_ENCODING, buffering=0)
586
except (OSError, IOError) as ex:
587
try:
588
warnMsg = "unable to create results file '%s' ('%s'). " % (conf.resultsFile, getUnicode(ex))
589
handle, conf.resultsFile = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.RESULTS, suffix=".csv")
590
os.close(handle)
591
conf.resultsFP = openFile(conf.resultsFile, "w+", UNICODE_ENCODING, buffering=0)
592
warnMsg += "Using temporary file '%s' instead" % conf.resultsFile
593
logger.warning(warnMsg)
594
except IOError as _:
595
errMsg = "unable to write to the temporary directory ('%s'). " % _
596
errMsg += "Please make sure that your disk is not full and "
597
errMsg += "that you have sufficient write permissions to "
598
errMsg += "create temporary files and/or directories"
599
raise SqlmapSystemException(errMsg)
600
601
if not found:
602
conf.resultsFP.writelines("Target URL,Place,Parameter,Technique(s),Note(s)%s" % os.linesep)
603
604
logger.info("using '%s' as the CSV results file in multiple targets mode" % conf.resultsFile)
605
606
def _createFilesDir():
607
"""
608
Create the file directory.
609
"""
610
611
if not any((conf.fileRead, conf.commonFiles)):
612
return
613
614
conf.filePath = paths.SQLMAP_FILES_PATH % conf.hostname
615
616
if not os.path.isdir(conf.filePath):
617
try:
618
os.makedirs(conf.filePath)
619
except OSError as ex:
620
tempDir = tempfile.mkdtemp(prefix="sqlmapfiles")
621
warnMsg = "unable to create files directory "
622
warnMsg += "'%s' (%s). " % (conf.filePath, getUnicode(ex))
623
warnMsg += "Using temporary directory '%s' instead" % getUnicode(tempDir)
624
logger.warning(warnMsg)
625
626
conf.filePath = tempDir
627
628
def _createDumpDir():
629
"""
630
Create the dump directory.
631
"""
632
633
if not conf.dumpTable and not conf.dumpAll and not conf.search:
634
return
635
636
conf.dumpPath = safeStringFormat(paths.SQLMAP_DUMP_PATH, conf.hostname)
637
638
if not os.path.isdir(conf.dumpPath):
639
try:
640
os.makedirs(conf.dumpPath)
641
except Exception as ex:
642
tempDir = tempfile.mkdtemp(prefix="sqlmapdump")
643
warnMsg = "unable to create dump directory "
644
warnMsg += "'%s' (%s). " % (conf.dumpPath, getUnicode(ex))
645
warnMsg += "Using temporary directory '%s' instead" % getUnicode(tempDir)
646
logger.warning(warnMsg)
647
648
conf.dumpPath = tempDir
649
650
def _configureDumper():
651
conf.dumper = dumper
652
conf.dumper.setOutputFile()
653
654
def _createTargetDirs():
655
"""
656
Create the output directory.
657
"""
658
659
conf.outputPath = os.path.join(getUnicode(paths.SQLMAP_OUTPUT_PATH), normalizeUnicode(getUnicode(conf.hostname)))
660
661
try:
662
if not os.path.isdir(conf.outputPath):
663
os.makedirs(conf.outputPath)
664
except (OSError, IOError, TypeError) as ex:
665
tempDir = tempfile.mkdtemp(prefix="sqlmapoutput")
666
warnMsg = "unable to create output directory "
667
warnMsg += "'%s' (%s). " % (conf.outputPath, getUnicode(ex))
668
warnMsg += "Using temporary directory '%s' instead" % getUnicode(tempDir)
669
logger.warning(warnMsg)
670
671
conf.outputPath = tempDir
672
673
conf.outputPath = getUnicode(conf.outputPath)
674
675
try:
676
with openFile(os.path.join(conf.outputPath, "target.txt"), "w+") as f:
677
f.write(getUnicode(kb.originalUrls.get(conf.url) or conf.url or conf.hostname))
678
f.write(" (%s)" % (HTTPMETHOD.POST if conf.data else HTTPMETHOD.GET))
679
f.write(" # %s" % getUnicode(subprocess.list2cmdline(sys.argv), encoding=sys.stdin.encoding))
680
if conf.data:
681
f.write("\n\n%s" % getUnicode(conf.data))
682
except IOError as ex:
683
if "denied" in getUnicode(ex):
684
errMsg = "you don't have enough permissions "
685
else:
686
errMsg = "something went wrong while trying "
687
errMsg += "to write to the output directory '%s' (%s)" % (paths.SQLMAP_OUTPUT_PATH, getSafeExString(ex))
688
689
raise SqlmapMissingPrivileges(errMsg)
690
except UnicodeError as ex:
691
warnMsg = "something went wrong while saving target data ('%s')" % getSafeExString(ex)
692
logger.warning(warnMsg)
693
694
_createDumpDir()
695
_createFilesDir()
696
_configureDumper()
697
698
def _setAuxOptions():
699
"""
700
Setup auxiliary (host-dependent) options
701
"""
702
703
kb.aliasName = randomStr(seed=hash(conf.hostname or ""))
704
705
def _restoreMergedOptions():
706
"""
707
Restore merged options (command line, configuration file and default values)
708
that could be possibly changed during the testing of previous target.
709
"""
710
711
for option in RESTORE_MERGED_OPTIONS:
712
conf[option] = mergedOptions[option]
713
714
def initTargetEnv():
715
"""
716
Initialize target environment.
717
"""
718
719
if conf.multipleTargets:
720
if conf.hashDB:
721
conf.hashDB.close()
722
723
if conf.cj:
724
resetCookieJar(conf.cj)
725
726
threadData = getCurrentThreadData()
727
threadData.reset()
728
729
conf.paramDict = {}
730
conf.parameters = {}
731
conf.hashDBFile = None
732
733
_setKnowledgeBaseAttributes(False)
734
_restoreMergedOptions()
735
_setDBMS()
736
737
if conf.data:
738
class _(six.text_type):
739
pass
740
741
kb.postUrlEncode = True
742
743
for key, value in conf.httpHeaders:
744
if key.upper() == HTTP_HEADER.CONTENT_TYPE.upper():
745
kb.postUrlEncode = "urlencoded" in value
746
break
747
748
if kb.postUrlEncode:
749
original = conf.data
750
conf.data = _(urldecode(conf.data))
751
setattr(conf.data, UNENCODED_ORIGINAL_VALUE, original)
752
kb.postSpaceToPlus = '+' in original
753
754
if conf.data and unArrayizeValue(conf.base64Parameter) == HTTPMETHOD.POST:
755
if '=' not in conf.data.strip('='):
756
try:
757
original = conf.data
758
conf.data = _(decodeBase64(conf.data, binary=False))
759
setattr(conf.data, UNENCODED_ORIGINAL_VALUE, original)
760
except:
761
pass
762
763
match = re.search(INJECT_HERE_REGEX, "%s %s %s" % (conf.url, conf.data, conf.httpHeaders))
764
kb.customInjectionMark = match.group(0) if match else CUSTOM_INJECTION_MARK_CHAR
765
766
def setupTargetEnv():
767
_createTargetDirs()
768
_setRequestParams()
769
_setHashDB()
770
_resumeHashDBValues()
771
_setResultsFile()
772
_setAuthCred()
773
_setAuxOptions()
774
775