Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sqlmapproject
GitHub Repository: sqlmapproject/sqlmap
Path: blob/master/lib/core/option.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
from __future__ import division
9
10
import codecs
11
import functools
12
import glob
13
import inspect
14
import json
15
import logging
16
import os
17
import random
18
import re
19
import socket
20
import sys
21
import tempfile
22
import threading
23
import time
24
import traceback
25
26
from lib.controller.checks import checkConnection
27
from lib.core.common import Backend
28
from lib.core.common import boldifyMessage
29
from lib.core.common import checkFile
30
from lib.core.common import dataToStdout
31
from lib.core.common import decodeStringEscape
32
from lib.core.common import fetchRandomAgent
33
from lib.core.common import filterNone
34
from lib.core.common import findLocalPort
35
from lib.core.common import findPageForms
36
from lib.core.common import getConsoleWidth
37
from lib.core.common import getFileItems
38
from lib.core.common import getFileType
39
from lib.core.common import getPublicTypeMembers
40
from lib.core.common import getSafeExString
41
from lib.core.common import intersect
42
from lib.core.common import normalizePath
43
from lib.core.common import ntToPosixSlashes
44
from lib.core.common import openFile
45
from lib.core.common import parseRequestFile
46
from lib.core.common import parseTargetDirect
47
from lib.core.common import paths
48
from lib.core.common import randomStr
49
from lib.core.common import readCachedFileContent
50
from lib.core.common import readInput
51
from lib.core.common import resetCookieJar
52
from lib.core.common import runningAsAdmin
53
from lib.core.common import safeExpandUser
54
from lib.core.common import safeFilepathEncode
55
from lib.core.common import saveConfig
56
from lib.core.common import setColor
57
from lib.core.common import setOptimize
58
from lib.core.common import setPaths
59
from lib.core.common import singleTimeWarnMessage
60
from lib.core.common import urldecode
61
from lib.core.compat import cmp
62
from lib.core.compat import round
63
from lib.core.compat import xrange
64
from lib.core.convert import getUnicode
65
from lib.core.data import conf
66
from lib.core.data import kb
67
from lib.core.data import logger
68
from lib.core.data import mergedOptions
69
from lib.core.data import queries
70
from lib.core.datatype import AttribDict
71
from lib.core.datatype import InjectionDict
72
from lib.core.datatype import OrderedSet
73
from lib.core.defaults import defaults
74
from lib.core.dicts import DBMS_DICT
75
from lib.core.dicts import DUMP_REPLACEMENTS
76
from lib.core.enums import ADJUST_TIME_DELAY
77
from lib.core.enums import AUTH_TYPE
78
from lib.core.enums import CUSTOM_LOGGING
79
from lib.core.enums import DUMP_FORMAT
80
from lib.core.enums import FORK
81
from lib.core.enums import HTTP_HEADER
82
from lib.core.enums import HTTPMETHOD
83
from lib.core.enums import MKSTEMP_PREFIX
84
from lib.core.enums import MOBILES
85
from lib.core.enums import OPTION_TYPE
86
from lib.core.enums import PAYLOAD
87
from lib.core.enums import PRIORITY
88
from lib.core.enums import PROXY_TYPE
89
from lib.core.enums import REFLECTIVE_COUNTER
90
from lib.core.enums import WIZARD
91
from lib.core.exception import SqlmapConnectionException
92
from lib.core.exception import SqlmapDataException
93
from lib.core.exception import SqlmapFilePathException
94
from lib.core.exception import SqlmapGenericException
95
from lib.core.exception import SqlmapInstallationException
96
from lib.core.exception import SqlmapMissingDependence
97
from lib.core.exception import SqlmapMissingMandatoryOptionException
98
from lib.core.exception import SqlmapMissingPrivileges
99
from lib.core.exception import SqlmapSilentQuitException
100
from lib.core.exception import SqlmapSyntaxException
101
from lib.core.exception import SqlmapSystemException
102
from lib.core.exception import SqlmapUnsupportedDBMSException
103
from lib.core.exception import SqlmapUserQuitException
104
from lib.core.exception import SqlmapValueException
105
from lib.core.log import FORMATTER
106
from lib.core.optiondict import optDict
107
from lib.core.settings import CODECS_LIST_PAGE
108
from lib.core.settings import CUSTOM_INJECTION_MARK_CHAR
109
from lib.core.settings import DBMS_ALIASES
110
from lib.core.settings import DEFAULT_GET_POST_DELIMITER
111
from lib.core.settings import DEFAULT_PAGE_ENCODING
112
from lib.core.settings import DEFAULT_TOR_HTTP_PORTS
113
from lib.core.settings import DEFAULT_TOR_SOCKS_PORTS
114
from lib.core.settings import DEFAULT_USER_AGENT
115
from lib.core.settings import DUMMY_URL
116
from lib.core.settings import IGNORE_CODE_WILDCARD
117
from lib.core.settings import IS_WIN
118
from lib.core.settings import KB_CHARS_BOUNDARY_CHAR
119
from lib.core.settings import KB_CHARS_LOW_FREQUENCY_ALPHABET
120
from lib.core.settings import LOCALHOST
121
from lib.core.settings import MAX_CONNECT_RETRIES
122
from lib.core.settings import MAX_NUMBER_OF_THREADS
123
from lib.core.settings import NULL
124
from lib.core.settings import PARAMETER_SPLITTING_REGEX
125
from lib.core.settings import PRECONNECT_CANDIDATE_TIMEOUT
126
from lib.core.settings import PROXY_ENVIRONMENT_VARIABLES
127
from lib.core.settings import SOCKET_PRE_CONNECT_QUEUE_SIZE
128
from lib.core.settings import SQLMAP_ENVIRONMENT_PREFIX
129
from lib.core.settings import SUPPORTED_DBMS
130
from lib.core.settings import SUPPORTED_OS
131
from lib.core.settings import TIME_DELAY_CANDIDATES
132
from lib.core.settings import UNKNOWN_DBMS_VERSION
133
from lib.core.settings import URI_INJECTABLE_REGEX
134
from lib.core.threads import getCurrentThreadData
135
from lib.core.threads import setDaemon
136
from lib.core.update import update
137
from lib.parse.configfile import configFileParser
138
from lib.parse.payloads import loadBoundaries
139
from lib.parse.payloads import loadPayloads
140
from lib.request.basic import checkCharEncoding
141
from lib.request.basicauthhandler import SmartHTTPBasicAuthHandler
142
from lib.request.chunkedhandler import ChunkedHandler
143
from lib.request.connect import Connect as Request
144
from lib.request.dns import DNSServer
145
from lib.request.httpshandler import HTTPSHandler
146
from lib.request.pkihandler import HTTPSPKIAuthHandler
147
from lib.request.rangehandler import HTTPRangeHandler
148
from lib.request.redirecthandler import SmartRedirectHandler
149
from lib.utils.crawler import crawl
150
from lib.utils.deps import checkDependencies
151
from lib.utils.har import HTTPCollectorFactory
152
from lib.utils.purge import purge
153
from lib.utils.search import search
154
from thirdparty import six
155
from thirdparty.keepalive import keepalive
156
from thirdparty.multipart import multipartpost
157
from thirdparty.six.moves import collections_abc as _collections
158
from thirdparty.six.moves import http_client as _http_client
159
from thirdparty.six.moves import http_cookiejar as _http_cookiejar
160
from thirdparty.six.moves import urllib as _urllib
161
from thirdparty.socks import socks
162
from xml.etree.ElementTree import ElementTree
163
164
authHandler = _urllib.request.BaseHandler()
165
chunkedHandler = ChunkedHandler()
166
httpsHandler = HTTPSHandler()
167
keepAliveHandler = keepalive.HTTPHandler()
168
proxyHandler = _urllib.request.ProxyHandler()
169
redirectHandler = SmartRedirectHandler()
170
rangeHandler = HTTPRangeHandler()
171
multipartPostHandler = multipartpost.MultipartPostHandler()
172
173
# Reference: https://mail.python.org/pipermail/python-list/2009-November/558615.html
174
try:
175
WindowsError
176
except NameError:
177
WindowsError = None
178
179
def _loadQueries():
180
"""
181
Loads queries from 'xml/queries.xml' file.
182
"""
183
184
def iterate(node, retVal=None):
185
class DictObject(object):
186
def __init__(self):
187
self.__dict__ = {}
188
189
def __contains__(self, name):
190
return name in self.__dict__
191
192
if retVal is None:
193
retVal = DictObject()
194
195
for child in node.findall("*"):
196
instance = DictObject()
197
retVal.__dict__[child.tag] = instance
198
if child.attrib:
199
instance.__dict__.update(child.attrib)
200
else:
201
iterate(child, instance)
202
203
return retVal
204
205
tree = ElementTree()
206
try:
207
tree.parse(paths.QUERIES_XML)
208
except Exception as ex:
209
errMsg = "something appears to be wrong with "
210
errMsg += "the file '%s' ('%s'). Please make " % (paths.QUERIES_XML, getSafeExString(ex))
211
errMsg += "sure that you haven't made any changes to it"
212
raise SqlmapInstallationException(errMsg)
213
214
for node in tree.findall("*"):
215
queries[node.attrib['value']] = iterate(node)
216
217
def _setMultipleTargets():
218
"""
219
Define a configuration parameter if we are running in multiple target
220
mode.
221
"""
222
223
initialTargetsCount = len(kb.targets)
224
seen = set()
225
226
if not conf.logFile:
227
return
228
229
debugMsg = "parsing targets list from '%s'" % conf.logFile
230
logger.debug(debugMsg)
231
232
if not os.path.exists(conf.logFile):
233
errMsg = "the specified list of targets does not exist"
234
raise SqlmapFilePathException(errMsg)
235
236
if checkFile(conf.logFile, False):
237
for target in parseRequestFile(conf.logFile):
238
url, _, data, _, _ = target
239
key = re.sub(r"(\w+=)[^%s ]*" % (conf.paramDel or DEFAULT_GET_POST_DELIMITER), r"\g<1>", "%s %s" % (url, data))
240
if key not in seen:
241
kb.targets.add(target)
242
seen.add(key)
243
244
elif os.path.isdir(conf.logFile):
245
files = os.listdir(conf.logFile)
246
files.sort()
247
248
for reqFile in files:
249
if not re.search(r"([\d]+)\-request", reqFile):
250
continue
251
252
for target in parseRequestFile(os.path.join(conf.logFile, reqFile)):
253
url, _, data, _, _ = target
254
key = re.sub(r"(\w+=)[^%s ]*" % (conf.paramDel or DEFAULT_GET_POST_DELIMITER), r"\g<1>", "%s %s" % (url, data))
255
if key not in seen:
256
kb.targets.add(target)
257
seen.add(key)
258
259
else:
260
errMsg = "the specified list of targets is not a file "
261
errMsg += "nor a directory"
262
raise SqlmapFilePathException(errMsg)
263
264
updatedTargetsCount = len(kb.targets)
265
266
if updatedTargetsCount > initialTargetsCount:
267
infoMsg = "sqlmap parsed %d " % (updatedTargetsCount - initialTargetsCount)
268
infoMsg += "(parameter unique) requests from the "
269
infoMsg += "targets list ready to be tested"
270
logger.info(infoMsg)
271
272
def _adjustLoggingFormatter():
273
"""
274
Solves problem of line deletition caused by overlapping logging messages
275
and retrieved data info in inference mode
276
"""
277
278
if hasattr(FORMATTER, '_format'):
279
return
280
281
def format(record):
282
message = FORMATTER._format(record)
283
message = boldifyMessage(message)
284
if kb.get("prependFlag"):
285
message = "\n%s" % message
286
kb.prependFlag = False
287
return message
288
289
FORMATTER._format = FORMATTER.format
290
FORMATTER.format = format
291
292
def _setRequestFromFile():
293
"""
294
This function checks if the way to make a HTTP request is through supplied
295
textual file, parses it and saves the information into the knowledge base.
296
"""
297
298
if conf.requestFile:
299
for requestFile in re.split(PARAMETER_SPLITTING_REGEX, conf.requestFile):
300
requestFile = safeExpandUser(requestFile)
301
url = None
302
seen = set()
303
304
if not checkFile(requestFile, False):
305
errMsg = "specified HTTP request file '%s' " % requestFile
306
errMsg += "does not exist"
307
raise SqlmapFilePathException(errMsg)
308
309
infoMsg = "parsing HTTP request from '%s'" % requestFile
310
logger.info(infoMsg)
311
312
for target in parseRequestFile(requestFile):
313
url = target[0]
314
if url not in seen:
315
kb.targets.add(target)
316
if len(kb.targets) > 1:
317
conf.multipleTargets = True
318
seen.add(url)
319
320
if url is None:
321
errMsg = "specified file '%s' " % requestFile
322
errMsg += "does not contain a usable HTTP request (with parameters)"
323
raise SqlmapDataException(errMsg)
324
325
if conf.secondReq:
326
conf.secondReq = safeExpandUser(conf.secondReq)
327
328
if not checkFile(conf.secondReq, False):
329
errMsg = "specified second-order HTTP request file '%s' " % conf.secondReq
330
errMsg += "does not exist"
331
raise SqlmapFilePathException(errMsg)
332
333
infoMsg = "parsing second-order HTTP request from '%s'" % conf.secondReq
334
logger.info(infoMsg)
335
336
try:
337
target = next(parseRequestFile(conf.secondReq, False))
338
kb.secondReq = target
339
except StopIteration:
340
errMsg = "specified second-order HTTP request file '%s' " % conf.secondReq
341
errMsg += "does not contain a valid HTTP request"
342
raise SqlmapDataException(errMsg)
343
344
def _setCrawler():
345
if not conf.crawlDepth:
346
return
347
348
if not conf.bulkFile:
349
if conf.url:
350
crawl(conf.url)
351
elif conf.requestFile and kb.targets:
352
target = next(iter(kb.targets))
353
crawl(target[0], target[2], target[3])
354
355
def _doSearch():
356
"""
357
This function performs search dorking, parses results
358
and saves the testable hosts into the knowledge base.
359
"""
360
361
if not conf.googleDork:
362
return
363
364
kb.data.onlyGETs = None
365
366
def retrieve():
367
links = search(conf.googleDork)
368
369
if not links:
370
errMsg = "unable to find results for your "
371
errMsg += "search dork expression"
372
raise SqlmapGenericException(errMsg)
373
374
for link in links:
375
link = urldecode(link)
376
if re.search(r"(.*?)\?(.+)", link) or conf.forms:
377
kb.targets.add((link, conf.method, conf.data, conf.cookie, None))
378
elif re.search(URI_INJECTABLE_REGEX, link, re.I):
379
if kb.data.onlyGETs is None and conf.data is None and not conf.googleDork:
380
message = "do you want to scan only results containing GET parameters? [Y/n] "
381
kb.data.onlyGETs = readInput(message, default='Y', boolean=True)
382
if not kb.data.onlyGETs or conf.googleDork:
383
kb.targets.add((link, conf.method, conf.data, conf.cookie, None))
384
385
return links
386
387
while True:
388
links = retrieve()
389
390
if kb.targets:
391
infoMsg = "found %d results for your " % len(links)
392
infoMsg += "search dork expression"
393
394
if not conf.forms:
395
infoMsg += ", "
396
397
if len(links) == len(kb.targets):
398
infoMsg += "all "
399
else:
400
infoMsg += "%d " % len(kb.targets)
401
402
infoMsg += "of them are testable targets"
403
404
logger.info(infoMsg)
405
break
406
407
else:
408
message = "found %d results " % len(links)
409
message += "for your search dork expression, but none of them "
410
message += "have GET parameters to test for SQL injection. "
411
message += "Do you want to skip to the next result page? [Y/n]"
412
413
if not readInput(message, default='Y', boolean=True):
414
raise SqlmapSilentQuitException
415
else:
416
conf.googlePage += 1
417
418
def _setStdinPipeTargets():
419
if conf.url:
420
return
421
422
if isinstance(conf.stdinPipe, _collections.Iterable):
423
infoMsg = "using 'STDIN' for parsing targets list"
424
logger.info(infoMsg)
425
426
class _(object):
427
def __init__(self):
428
self.__rest = OrderedSet()
429
430
def __iter__(self):
431
return self
432
433
def __next__(self):
434
return self.next()
435
436
def next(self):
437
try:
438
line = next(conf.stdinPipe)
439
except (IOError, OSError, TypeError, UnicodeDecodeError):
440
line = None
441
442
if line:
443
match = re.search(r"\b(https?://[^\s'\"]+|[\w.]+\.\w{2,3}[/\w+]*\?[^\s'\"]+)", line, re.I)
444
if match:
445
return (match.group(0), conf.method, conf.data, conf.cookie, None)
446
elif self.__rest:
447
return self.__rest.pop()
448
449
raise StopIteration()
450
451
def add(self, elem):
452
self.__rest.add(elem)
453
454
kb.targets = _()
455
456
def _setBulkMultipleTargets():
457
if not conf.bulkFile:
458
return
459
460
conf.bulkFile = safeExpandUser(conf.bulkFile)
461
462
infoMsg = "parsing multiple targets list from '%s'" % conf.bulkFile
463
logger.info(infoMsg)
464
465
if not checkFile(conf.bulkFile, False):
466
errMsg = "the specified bulk file "
467
errMsg += "does not exist"
468
raise SqlmapFilePathException(errMsg)
469
470
found = False
471
for line in getFileItems(conf.bulkFile):
472
if conf.scope and not re.search(conf.scope, line, re.I):
473
continue
474
475
if re.match(r"[^ ]+\?(.+)", line, re.I) or kb.customInjectionMark in line or conf.data:
476
found = True
477
kb.targets.add((line.strip(), conf.method, conf.data, conf.cookie, None))
478
479
if not found and not conf.forms and not conf.crawlDepth:
480
warnMsg = "no usable links found (with GET parameters)"
481
logger.warning(warnMsg)
482
483
def _findPageForms():
484
if not conf.forms or conf.crawlDepth:
485
return
486
487
if conf.url and not checkConnection():
488
return
489
490
found = False
491
infoMsg = "searching for forms"
492
logger.info(infoMsg)
493
494
if not any((conf.bulkFile, conf.googleDork)):
495
page, _, _ = Request.queryPage(content=True, ignoreSecondOrder=True)
496
if findPageForms(page, conf.url, True, True):
497
found = True
498
else:
499
if conf.bulkFile:
500
targets = getFileItems(conf.bulkFile)
501
elif conf.googleDork:
502
targets = [_[0] for _ in kb.targets]
503
kb.targets.clear()
504
else:
505
targets = []
506
507
for i in xrange(len(targets)):
508
try:
509
target = targets[i].strip()
510
511
if not re.search(r"(?i)\Ahttp[s]*://", target):
512
target = "http://%s" % target
513
514
page, _, _ = Request.getPage(url=target.strip(), cookie=conf.cookie, crawling=True, raise404=False)
515
if findPageForms(page, target, False, True):
516
found = True
517
518
if conf.verbose in (1, 2):
519
status = '%d/%d links visited (%d%%)' % (i + 1, len(targets), round(100.0 * (i + 1) / len(targets)))
520
dataToStdout("\r[%s] [INFO] %s" % (time.strftime("%X"), status), True)
521
except KeyboardInterrupt:
522
break
523
except Exception as ex:
524
errMsg = "problem occurred while searching for forms at '%s' ('%s')" % (target, getSafeExString(ex))
525
logger.error(errMsg)
526
527
if not found:
528
warnMsg = "no forms found"
529
logger.warning(warnMsg)
530
531
def _setDBMSAuthentication():
532
"""
533
Check and set the DBMS authentication credentials to run statements as
534
another user, not the session user
535
"""
536
537
if not conf.dbmsCred:
538
return
539
540
debugMsg = "setting the DBMS authentication credentials"
541
logger.debug(debugMsg)
542
543
match = re.search(r"^(.+?):(.*?)$", conf.dbmsCred)
544
545
if not match:
546
errMsg = "DBMS authentication credentials value must be in format "
547
errMsg += "username:password"
548
raise SqlmapSyntaxException(errMsg)
549
550
conf.dbmsUsername = match.group(1)
551
conf.dbmsPassword = match.group(2)
552
553
def _setMetasploit():
554
if not conf.osPwn and not conf.osSmb and not conf.osBof:
555
return
556
557
debugMsg = "setting the takeover out-of-band functionality"
558
logger.debug(debugMsg)
559
560
msfEnvPathExists = False
561
562
if IS_WIN:
563
try:
564
__import__("win32file")
565
except ImportError:
566
errMsg = "sqlmap requires third-party module 'pywin32' "
567
errMsg += "in order to use Metasploit functionalities on "
568
errMsg += "Windows. You can download it from "
569
errMsg += "'https://github.com/mhammond/pywin32'"
570
raise SqlmapMissingDependence(errMsg)
571
572
if not conf.msfPath:
573
for candidate in os.environ.get("PATH", "").split(';'):
574
if all(_ in candidate for _ in ("metasploit", "bin")):
575
conf.msfPath = os.path.dirname(candidate.rstrip('\\'))
576
break
577
578
if conf.osSmb:
579
isAdmin = runningAsAdmin()
580
581
if not isAdmin:
582
errMsg = "you need to run sqlmap as an administrator "
583
errMsg += "if you want to perform a SMB relay attack because "
584
errMsg += "it will need to listen on a user-specified SMB "
585
errMsg += "TCP port for incoming connection attempts"
586
raise SqlmapMissingPrivileges(errMsg)
587
588
if conf.msfPath:
589
for path in (conf.msfPath, os.path.join(conf.msfPath, "bin")):
590
if any(os.path.exists(normalizePath(os.path.join(path, "%s%s" % (_, ".bat" if IS_WIN else "")))) for _ in ("msfcli", "msfconsole")):
591
msfEnvPathExists = True
592
if all(os.path.exists(normalizePath(os.path.join(path, "%s%s" % (_, ".bat" if IS_WIN else "")))) for _ in ("msfvenom",)):
593
kb.oldMsf = False
594
elif all(os.path.exists(normalizePath(os.path.join(path, "%s%s" % (_, ".bat" if IS_WIN else "")))) for _ in ("msfencode", "msfpayload")):
595
kb.oldMsf = True
596
else:
597
msfEnvPathExists = False
598
599
conf.msfPath = path
600
break
601
602
if msfEnvPathExists:
603
debugMsg = "provided Metasploit Framework path "
604
debugMsg += "'%s' is valid" % conf.msfPath
605
logger.debug(debugMsg)
606
else:
607
warnMsg = "the provided Metasploit Framework path "
608
warnMsg += "'%s' is not valid. The cause could " % conf.msfPath
609
warnMsg += "be that the path does not exists or that one "
610
warnMsg += "or more of the needed Metasploit executables "
611
warnMsg += "within msfcli, msfconsole, msfencode and "
612
warnMsg += "msfpayload do not exist"
613
logger.warning(warnMsg)
614
else:
615
warnMsg = "you did not provide the local path where Metasploit "
616
warnMsg += "Framework is installed"
617
logger.warning(warnMsg)
618
619
if not msfEnvPathExists:
620
warnMsg = "sqlmap is going to look for Metasploit Framework "
621
warnMsg += "installation inside the environment path(s)"
622
logger.warning(warnMsg)
623
624
envPaths = os.environ.get("PATH", "").split(";" if IS_WIN else ":")
625
626
for envPath in envPaths:
627
envPath = envPath.replace(";", "")
628
629
if any(os.path.exists(normalizePath(os.path.join(envPath, "%s%s" % (_, ".bat" if IS_WIN else "")))) for _ in ("msfcli", "msfconsole")):
630
msfEnvPathExists = True
631
if all(os.path.exists(normalizePath(os.path.join(envPath, "%s%s" % (_, ".bat" if IS_WIN else "")))) for _ in ("msfvenom",)):
632
kb.oldMsf = False
633
elif all(os.path.exists(normalizePath(os.path.join(envPath, "%s%s" % (_, ".bat" if IS_WIN else "")))) for _ in ("msfencode", "msfpayload")):
634
kb.oldMsf = True
635
else:
636
msfEnvPathExists = False
637
638
if msfEnvPathExists:
639
infoMsg = "Metasploit Framework has been found "
640
infoMsg += "installed in the '%s' path" % envPath
641
logger.info(infoMsg)
642
643
conf.msfPath = envPath
644
645
break
646
647
if not msfEnvPathExists:
648
errMsg = "unable to locate Metasploit Framework installation. "
649
errMsg += "You can get it at 'https://www.metasploit.com/download/'"
650
raise SqlmapFilePathException(errMsg)
651
652
def _setWriteFile():
653
if not conf.fileWrite:
654
return
655
656
debugMsg = "setting the write file functionality"
657
logger.debug(debugMsg)
658
659
if not os.path.exists(conf.fileWrite):
660
errMsg = "the provided local file '%s' does not exist" % conf.fileWrite
661
raise SqlmapFilePathException(errMsg)
662
663
if not conf.fileDest:
664
errMsg = "you did not provide the back-end DBMS absolute path "
665
errMsg += "where you want to write the local file '%s'" % conf.fileWrite
666
raise SqlmapMissingMandatoryOptionException(errMsg)
667
668
conf.fileWriteType = getFileType(conf.fileWrite)
669
670
def _setOS():
671
"""
672
Force the back-end DBMS operating system option.
673
"""
674
675
if not conf.os:
676
return
677
678
if conf.os.lower() not in SUPPORTED_OS:
679
errMsg = "you provided an unsupported back-end DBMS operating "
680
errMsg += "system. The supported DBMS operating systems for OS "
681
errMsg += "and file system access are %s. " % ', '.join([o.capitalize() for o in SUPPORTED_OS])
682
errMsg += "If you do not know the back-end DBMS underlying OS, "
683
errMsg += "do not provide it and sqlmap will fingerprint it for "
684
errMsg += "you."
685
raise SqlmapUnsupportedDBMSException(errMsg)
686
687
debugMsg = "forcing back-end DBMS operating system to user defined "
688
debugMsg += "value '%s'" % conf.os
689
logger.debug(debugMsg)
690
691
Backend.setOs(conf.os)
692
693
def _setTechnique():
694
validTechniques = sorted(getPublicTypeMembers(PAYLOAD.TECHNIQUE), key=lambda x: x[1])
695
validLetters = [_[0][0].upper() for _ in validTechniques]
696
697
if conf.technique and isinstance(conf.technique, six.string_types):
698
_ = []
699
700
for letter in conf.technique.upper():
701
if letter not in validLetters:
702
errMsg = "value for --technique must be a string composed "
703
errMsg += "by the letters %s. Refer to the " % ", ".join(validLetters)
704
errMsg += "user's manual for details"
705
raise SqlmapSyntaxException(errMsg)
706
707
for validTech, validInt in validTechniques:
708
if letter == validTech[0]:
709
_.append(validInt)
710
break
711
712
conf.technique = _
713
714
def _setDBMS():
715
"""
716
Force the back-end DBMS option.
717
"""
718
719
if not conf.dbms:
720
return
721
722
debugMsg = "forcing back-end DBMS to user defined value"
723
logger.debug(debugMsg)
724
725
conf.dbms = conf.dbms.lower()
726
regex = re.search(r"%s ([\d\.]+)" % ("(%s)" % "|".join(SUPPORTED_DBMS)), conf.dbms, re.I)
727
728
if regex:
729
conf.dbms = regex.group(1)
730
Backend.setVersion(regex.group(2))
731
732
if conf.dbms not in SUPPORTED_DBMS:
733
errMsg = "you provided an unsupported back-end database management "
734
errMsg += "system. Supported DBMSes are as follows: %s. " % ', '.join(sorted((_ for _ in (list(DBMS_DICT) + getPublicTypeMembers(FORK, True))), key=str.lower))
735
errMsg += "If you do not know the back-end DBMS, do not provide "
736
errMsg += "it and sqlmap will fingerprint it for you."
737
raise SqlmapUnsupportedDBMSException(errMsg)
738
739
for dbms, aliases in DBMS_ALIASES:
740
if conf.dbms in aliases:
741
conf.dbms = dbms
742
743
break
744
745
def _listTamperingFunctions():
746
"""
747
Lists available tamper functions
748
"""
749
750
if conf.listTampers:
751
infoMsg = "listing available tamper scripts\n"
752
logger.info(infoMsg)
753
754
for script in sorted(glob.glob(os.path.join(paths.SQLMAP_TAMPER_PATH, "*.py"))):
755
content = openFile(script, "rb").read()
756
match = re.search(r'(?s)__priority__.+"""(.+)"""', content)
757
if match:
758
comment = match.group(1).strip()
759
dataToStdout("* %s - %s\n" % (setColor(os.path.basename(script), "yellow"), re.sub(r" *\n *", " ", comment.split("\n\n")[0].strip())))
760
761
def _setTamperingFunctions():
762
"""
763
Loads tampering functions from given script(s)
764
"""
765
766
if conf.tamper:
767
last_priority = PRIORITY.HIGHEST
768
check_priority = True
769
resolve_priorities = False
770
priorities = []
771
772
for script in re.split(PARAMETER_SPLITTING_REGEX, conf.tamper):
773
found = False
774
775
path = safeFilepathEncode(paths.SQLMAP_TAMPER_PATH)
776
script = safeFilepathEncode(script.strip())
777
778
try:
779
if not script:
780
continue
781
782
elif os.path.exists(os.path.join(path, script if script.endswith(".py") else "%s.py" % script)):
783
script = os.path.join(path, script if script.endswith(".py") else "%s.py" % script)
784
785
elif not os.path.exists(script):
786
errMsg = "tamper script '%s' does not exist" % script
787
raise SqlmapFilePathException(errMsg)
788
789
elif not script.endswith(".py"):
790
errMsg = "tamper script '%s' should have an extension '.py'" % script
791
raise SqlmapSyntaxException(errMsg)
792
except UnicodeDecodeError:
793
errMsg = "invalid character provided in option '--tamper'"
794
raise SqlmapSyntaxException(errMsg)
795
796
dirname, filename = os.path.split(script)
797
dirname = os.path.abspath(dirname)
798
799
infoMsg = "loading tamper module '%s'" % filename[:-3]
800
logger.info(infoMsg)
801
802
if not os.path.exists(os.path.join(dirname, "__init__.py")):
803
errMsg = "make sure that there is an empty file '__init__.py' "
804
errMsg += "inside of tamper scripts directory '%s'" % dirname
805
raise SqlmapGenericException(errMsg)
806
807
if dirname not in sys.path:
808
sys.path.insert(0, dirname)
809
810
try:
811
module = __import__(safeFilepathEncode(filename[:-3]))
812
except Exception as ex:
813
raise SqlmapSyntaxException("cannot import tamper module '%s' (%s)" % (getUnicode(filename[:-3]), getSafeExString(ex)))
814
815
priority = PRIORITY.NORMAL if not hasattr(module, "__priority__") else module.__priority__
816
priority = priority if priority is not None else PRIORITY.LOWEST
817
818
for name, function in inspect.getmembers(module, inspect.isfunction):
819
if name == "tamper" and (hasattr(inspect, "signature") and all(_ in inspect.signature(function).parameters for _ in ("payload", "kwargs")) or inspect.getargspec(function).args and inspect.getargspec(function).keywords == "kwargs"):
820
found = True
821
kb.tamperFunctions.append(function)
822
function.__name__ = module.__name__
823
824
if check_priority and priority > last_priority:
825
message = "it appears that you might have mixed "
826
message += "the order of tamper scripts. "
827
message += "Do you want to auto resolve this? [Y/n/q] "
828
choice = readInput(message, default='Y').upper()
829
830
if choice == 'N':
831
resolve_priorities = False
832
elif choice == 'Q':
833
raise SqlmapUserQuitException
834
else:
835
resolve_priorities = True
836
837
check_priority = False
838
839
priorities.append((priority, function))
840
last_priority = priority
841
842
break
843
elif name == "dependencies":
844
try:
845
function()
846
except Exception as ex:
847
errMsg = "error occurred while checking dependencies "
848
errMsg += "for tamper module '%s' ('%s')" % (getUnicode(filename[:-3]), getSafeExString(ex))
849
raise SqlmapGenericException(errMsg)
850
851
if not found:
852
errMsg = "missing function 'tamper(payload, **kwargs)' "
853
errMsg += "in tamper script '%s'" % script
854
raise SqlmapGenericException(errMsg)
855
856
if kb.tamperFunctions and len(kb.tamperFunctions) > 3:
857
warnMsg = "using too many tamper scripts is usually not "
858
warnMsg += "a good idea"
859
logger.warning(warnMsg)
860
861
if resolve_priorities and priorities:
862
priorities.sort(key=functools.cmp_to_key(lambda a, b: cmp(a[0], b[0])), reverse=True)
863
kb.tamperFunctions = []
864
865
for _, function in priorities:
866
kb.tamperFunctions.append(function)
867
868
def _setPreprocessFunctions():
869
"""
870
Loads preprocess function(s) from given script(s)
871
"""
872
873
if conf.preprocess:
874
for script in re.split(PARAMETER_SPLITTING_REGEX, conf.preprocess):
875
found = False
876
function = None
877
878
script = safeFilepathEncode(script.strip())
879
880
try:
881
if not script:
882
continue
883
884
if not os.path.exists(script):
885
errMsg = "preprocess script '%s' does not exist" % script
886
raise SqlmapFilePathException(errMsg)
887
888
elif not script.endswith(".py"):
889
errMsg = "preprocess script '%s' should have an extension '.py'" % script
890
raise SqlmapSyntaxException(errMsg)
891
except UnicodeDecodeError:
892
errMsg = "invalid character provided in option '--preprocess'"
893
raise SqlmapSyntaxException(errMsg)
894
895
dirname, filename = os.path.split(script)
896
dirname = os.path.abspath(dirname)
897
898
infoMsg = "loading preprocess module '%s'" % filename[:-3]
899
logger.info(infoMsg)
900
901
if not os.path.exists(os.path.join(dirname, "__init__.py")):
902
errMsg = "make sure that there is an empty file '__init__.py' "
903
errMsg += "inside of preprocess scripts directory '%s'" % dirname
904
raise SqlmapGenericException(errMsg)
905
906
if dirname not in sys.path:
907
sys.path.insert(0, dirname)
908
909
try:
910
module = __import__(safeFilepathEncode(filename[:-3]))
911
except Exception as ex:
912
raise SqlmapSyntaxException("cannot import preprocess module '%s' (%s)" % (getUnicode(filename[:-3]), getSafeExString(ex)))
913
914
for name, function in inspect.getmembers(module, inspect.isfunction):
915
try:
916
if name == "preprocess" and inspect.getargspec(function).args and all(_ in inspect.getargspec(function).args for _ in ("req",)):
917
found = True
918
919
kb.preprocessFunctions.append(function)
920
function.__name__ = module.__name__
921
922
break
923
except ValueError: # Note: https://github.com/sqlmapproject/sqlmap/issues/4357
924
pass
925
926
if not found:
927
errMsg = "missing function 'preprocess(req)' "
928
errMsg += "in preprocess script '%s'" % script
929
raise SqlmapGenericException(errMsg)
930
else:
931
try:
932
function(_urllib.request.Request("http://localhost"))
933
except Exception as ex:
934
tbMsg = traceback.format_exc()
935
936
if conf.debug:
937
dataToStdout(tbMsg)
938
939
handle, filename = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.PREPROCESS, suffix=".py")
940
os.close(handle)
941
942
openFile(filename, "w+b").write("#!/usr/bin/env\n\ndef preprocess(req):\n pass\n")
943
openFile(os.path.join(os.path.dirname(filename), "__init__.py"), "w+b").write("pass")
944
945
errMsg = "function 'preprocess(req)' "
946
errMsg += "in preprocess script '%s' " % script
947
errMsg += "had issues in a test run ('%s'). " % getSafeExString(ex)
948
errMsg += "You can find a template script at '%s'" % filename
949
raise SqlmapGenericException(errMsg)
950
951
def _setPostprocessFunctions():
952
"""
953
Loads postprocess function(s) from given script(s)
954
"""
955
956
if conf.postprocess:
957
for script in re.split(PARAMETER_SPLITTING_REGEX, conf.postprocess):
958
found = False
959
function = None
960
961
script = safeFilepathEncode(script.strip())
962
963
try:
964
if not script:
965
continue
966
967
if not os.path.exists(script):
968
errMsg = "postprocess script '%s' does not exist" % script
969
raise SqlmapFilePathException(errMsg)
970
971
elif not script.endswith(".py"):
972
errMsg = "postprocess script '%s' should have an extension '.py'" % script
973
raise SqlmapSyntaxException(errMsg)
974
except UnicodeDecodeError:
975
errMsg = "invalid character provided in option '--postprocess'"
976
raise SqlmapSyntaxException(errMsg)
977
978
dirname, filename = os.path.split(script)
979
dirname = os.path.abspath(dirname)
980
981
infoMsg = "loading postprocess module '%s'" % filename[:-3]
982
logger.info(infoMsg)
983
984
if not os.path.exists(os.path.join(dirname, "__init__.py")):
985
errMsg = "make sure that there is an empty file '__init__.py' "
986
errMsg += "inside of postprocess scripts directory '%s'" % dirname
987
raise SqlmapGenericException(errMsg)
988
989
if dirname not in sys.path:
990
sys.path.insert(0, dirname)
991
992
try:
993
module = __import__(safeFilepathEncode(filename[:-3]))
994
except Exception as ex:
995
raise SqlmapSyntaxException("cannot import postprocess module '%s' (%s)" % (getUnicode(filename[:-3]), getSafeExString(ex)))
996
997
for name, function in inspect.getmembers(module, inspect.isfunction):
998
if name == "postprocess" and inspect.getargspec(function).args and all(_ in inspect.getargspec(function).args for _ in ("page", "headers", "code")):
999
found = True
1000
1001
kb.postprocessFunctions.append(function)
1002
function.__name__ = module.__name__
1003
1004
break
1005
1006
if not found:
1007
errMsg = "missing function 'postprocess(page, headers=None, code=None)' "
1008
errMsg += "in postprocess script '%s'" % script
1009
raise SqlmapGenericException(errMsg)
1010
else:
1011
try:
1012
_, _, _ = function("", {}, None)
1013
except:
1014
handle, filename = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.PREPROCESS, suffix=".py")
1015
os.close(handle)
1016
1017
openFile(filename, "w+b").write("#!/usr/bin/env\n\ndef postprocess(page, headers=None, code=None):\n return page, headers, code\n")
1018
openFile(os.path.join(os.path.dirname(filename), "__init__.py"), "w+b").write("pass")
1019
1020
errMsg = "function 'postprocess(page, headers=None, code=None)' "
1021
errMsg += "in postprocess script '%s' " % script
1022
errMsg += "should return a tuple '(page, headers, code)' "
1023
errMsg += "(Note: find template script at '%s')" % filename
1024
raise SqlmapGenericException(errMsg)
1025
1026
def _setThreads():
1027
if not isinstance(conf.threads, int) or conf.threads <= 0:
1028
conf.threads = 1
1029
1030
def _setDNSCache():
1031
"""
1032
Makes a cached version of socket._getaddrinfo to avoid subsequent DNS requests.
1033
"""
1034
1035
def _getaddrinfo(*args, **kwargs):
1036
if args in kb.cache.addrinfo:
1037
return kb.cache.addrinfo[args]
1038
1039
else:
1040
kb.cache.addrinfo[args] = socket._getaddrinfo(*args, **kwargs)
1041
return kb.cache.addrinfo[args]
1042
1043
if not hasattr(socket, "_getaddrinfo"):
1044
socket._getaddrinfo = socket.getaddrinfo
1045
socket.getaddrinfo = _getaddrinfo
1046
1047
def _setSocketPreConnect():
1048
"""
1049
Makes a pre-connect version of socket.create_connection
1050
"""
1051
1052
if conf.disablePrecon:
1053
return
1054
1055
def _thread():
1056
while kb.get("threadContinue") and not conf.get("disablePrecon"):
1057
try:
1058
for key in socket._ready:
1059
if len(socket._ready[key]) < SOCKET_PRE_CONNECT_QUEUE_SIZE:
1060
s = socket.create_connection(*key[0], **dict(key[1]))
1061
with kb.locks.socket:
1062
socket._ready[key].append((s, time.time()))
1063
except KeyboardInterrupt:
1064
break
1065
except:
1066
pass
1067
finally:
1068
time.sleep(0.01)
1069
1070
def create_connection(*args, **kwargs):
1071
retVal = None
1072
1073
key = (tuple(args), frozenset(kwargs.items()))
1074
with kb.locks.socket:
1075
if key not in socket._ready:
1076
socket._ready[key] = []
1077
1078
while len(socket._ready[key]) > 0:
1079
candidate, created = socket._ready[key].pop(0)
1080
if (time.time() - created) < PRECONNECT_CANDIDATE_TIMEOUT:
1081
retVal = candidate
1082
break
1083
else:
1084
try:
1085
candidate.shutdown(socket.SHUT_RDWR)
1086
candidate.close()
1087
except socket.error:
1088
pass
1089
1090
if not retVal:
1091
retVal = socket._create_connection(*args, **kwargs)
1092
1093
return retVal
1094
1095
if not hasattr(socket, "_create_connection"):
1096
socket._ready = {}
1097
socket._create_connection = socket.create_connection
1098
socket.create_connection = create_connection
1099
1100
thread = threading.Thread(target=_thread)
1101
setDaemon(thread)
1102
thread.start()
1103
1104
def _setHTTPHandlers():
1105
"""
1106
Check and set the HTTP/SOCKS proxy for all HTTP requests.
1107
"""
1108
1109
with kb.locks.handlers:
1110
if conf.proxyList:
1111
conf.proxy = conf.proxyList[0]
1112
conf.proxyList = conf.proxyList[1:] + conf.proxyList[:1]
1113
1114
if len(conf.proxyList) > 1:
1115
infoMsg = "loading proxy '%s' from a supplied proxy list file" % conf.proxy
1116
logger.info(infoMsg)
1117
1118
elif not conf.proxy:
1119
if conf.hostname in ("localhost", "127.0.0.1") or conf.ignoreProxy:
1120
proxyHandler.proxies = {}
1121
1122
if conf.proxy:
1123
debugMsg = "setting the HTTP/SOCKS proxy for all HTTP requests"
1124
logger.debug(debugMsg)
1125
1126
try:
1127
_ = _urllib.parse.urlsplit(conf.proxy)
1128
except Exception as ex:
1129
errMsg = "invalid proxy address '%s' ('%s')" % (conf.proxy, getSafeExString(ex))
1130
raise SqlmapSyntaxException(errMsg)
1131
1132
match = re.search(r"\A([^:]*):([^:]*)@([^@]+)\Z", _.netloc)
1133
if match:
1134
username, password = match.group(1), match.group(2)
1135
else:
1136
username, password = None, None
1137
1138
hostnamePort = _.netloc.rsplit('@', 1)[-1].rsplit(":", 1)
1139
1140
scheme = _.scheme.upper()
1141
hostname = hostnamePort[0]
1142
port = None
1143
1144
if len(hostnamePort) == 2:
1145
try:
1146
port = int(hostnamePort[1])
1147
except:
1148
pass # drops into the next check block
1149
1150
if not all((scheme, hasattr(PROXY_TYPE, scheme), hostname, port)):
1151
errMsg = "proxy value must be in format '(%s)://address:port'" % "|".join(_[0].lower() for _ in getPublicTypeMembers(PROXY_TYPE))
1152
raise SqlmapSyntaxException(errMsg)
1153
1154
if conf.proxyCred:
1155
_ = re.search(r"\A(.*?):(.*?)\Z", conf.proxyCred)
1156
if not _:
1157
errMsg = "proxy authentication credentials "
1158
errMsg += "value must be in format username:password"
1159
raise SqlmapSyntaxException(errMsg)
1160
else:
1161
username = _.group(1)
1162
password = _.group(2)
1163
1164
if scheme in (PROXY_TYPE.SOCKS4, PROXY_TYPE.SOCKS5):
1165
proxyHandler.proxies = {}
1166
1167
if scheme == PROXY_TYPE.SOCKS4:
1168
warnMsg = "SOCKS4 does not support resolving (DNS) names (i.e. causing DNS leakage)"
1169
singleTimeWarnMessage(warnMsg)
1170
1171
socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5 if scheme == PROXY_TYPE.SOCKS5 else socks.PROXY_TYPE_SOCKS4, hostname, port, username=username, password=password)
1172
socks.wrapmodule(_http_client)
1173
else:
1174
socks.unwrapmodule(_http_client)
1175
1176
if conf.proxyCred:
1177
# Reference: http://stackoverflow.com/questions/34079/how-to-specify-an-authenticated-proxy-for-a-python-http-connection
1178
proxyString = "%s@" % conf.proxyCred
1179
else:
1180
proxyString = ""
1181
1182
proxyString += "%s:%d" % (hostname, port)
1183
proxyHandler.proxies = kb.proxies = {"http": proxyString, "https": proxyString}
1184
1185
proxyHandler.__init__(proxyHandler.proxies)
1186
1187
if not proxyHandler.proxies:
1188
for _ in ("http", "https"):
1189
if hasattr(proxyHandler, "%s_open" % _):
1190
delattr(proxyHandler, "%s_open" % _)
1191
1192
debugMsg = "creating HTTP requests opener object"
1193
logger.debug(debugMsg)
1194
1195
handlers = filterNone([multipartPostHandler, proxyHandler if proxyHandler.proxies else None, authHandler, redirectHandler, rangeHandler, chunkedHandler if conf.chunked else None, httpsHandler])
1196
1197
if not conf.dropSetCookie:
1198
if not conf.loadCookies:
1199
conf.cj = _http_cookiejar.CookieJar()
1200
else:
1201
conf.cj = _http_cookiejar.MozillaCookieJar()
1202
resetCookieJar(conf.cj)
1203
1204
handlers.append(_urllib.request.HTTPCookieProcessor(conf.cj))
1205
1206
# Reference: http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html
1207
if conf.keepAlive:
1208
warnMsg = "persistent HTTP(s) connections, Keep-Alive, has "
1209
warnMsg += "been disabled because of its incompatibility "
1210
1211
if conf.proxy:
1212
warnMsg += "with HTTP(s) proxy"
1213
logger.warning(warnMsg)
1214
elif conf.authType:
1215
warnMsg += "with authentication methods"
1216
logger.warning(warnMsg)
1217
else:
1218
handlers.append(keepAliveHandler)
1219
1220
opener = _urllib.request.build_opener(*handlers)
1221
opener.addheaders = [] # Note: clearing default "User-Agent: Python-urllib/X.Y"
1222
_urllib.request.install_opener(opener)
1223
1224
def _setSafeVisit():
1225
"""
1226
Check and set the safe visit options.
1227
"""
1228
if not any((conf.safeUrl, conf.safeReqFile)):
1229
return
1230
1231
if conf.safeReqFile:
1232
checkFile(conf.safeReqFile)
1233
1234
raw = readCachedFileContent(conf.safeReqFile)
1235
match = re.search(r"\A([A-Z]+) ([^ ]+) HTTP/[0-9.]+\Z", raw.split('\n')[0].strip())
1236
1237
if match:
1238
kb.safeReq.method = match.group(1)
1239
kb.safeReq.url = match.group(2)
1240
kb.safeReq.headers = {}
1241
1242
for line in raw.split('\n')[1:]:
1243
line = line.strip()
1244
if line and ':' in line:
1245
key, value = line.split(':', 1)
1246
value = value.strip()
1247
kb.safeReq.headers[key] = value
1248
if key.upper() == HTTP_HEADER.HOST.upper():
1249
if not value.startswith("http"):
1250
scheme = "http"
1251
if value.endswith(":443"):
1252
scheme = "https"
1253
value = "%s://%s" % (scheme, value)
1254
kb.safeReq.url = _urllib.parse.urljoin(value, kb.safeReq.url)
1255
else:
1256
break
1257
1258
post = None
1259
1260
if '\r\n\r\n' in raw:
1261
post = raw[raw.find('\r\n\r\n') + 4:]
1262
elif '\n\n' in raw:
1263
post = raw[raw.find('\n\n') + 2:]
1264
1265
if post and post.strip():
1266
kb.safeReq.post = post
1267
else:
1268
kb.safeReq.post = None
1269
else:
1270
errMsg = "invalid format of a safe request file"
1271
raise SqlmapSyntaxException(errMsg)
1272
else:
1273
if not re.search(r"(?i)\Ahttp[s]*://", conf.safeUrl):
1274
if ":443/" in conf.safeUrl:
1275
conf.safeUrl = "https://%s" % conf.safeUrl
1276
else:
1277
conf.safeUrl = "http://%s" % conf.safeUrl
1278
1279
if (conf.safeFreq or 0) <= 0:
1280
errMsg = "please provide a valid value (>0) for safe frequency ('--safe-freq') while using safe visit features"
1281
raise SqlmapSyntaxException(errMsg)
1282
1283
def _setPrefixSuffix():
1284
if conf.prefix is not None and conf.suffix is not None:
1285
# Create a custom boundary object for user's supplied prefix
1286
# and suffix
1287
boundary = AttribDict()
1288
1289
boundary.level = 1
1290
boundary.clause = [0]
1291
boundary.where = [1, 2, 3]
1292
boundary.prefix = conf.prefix
1293
boundary.suffix = conf.suffix
1294
1295
if " like" in boundary.suffix.lower():
1296
if "'" in boundary.suffix.lower():
1297
boundary.ptype = 3
1298
elif '"' in boundary.suffix.lower():
1299
boundary.ptype = 5
1300
elif "'" in boundary.suffix:
1301
boundary.ptype = 2
1302
elif '"' in boundary.suffix:
1303
boundary.ptype = 4
1304
else:
1305
boundary.ptype = 1
1306
1307
# user who provides --prefix/--suffix does not want other boundaries
1308
# to be tested for
1309
conf.boundaries = [boundary]
1310
1311
def _setAuthCred():
1312
"""
1313
Adds authentication credentials (if any) for current target to the password manager
1314
(used by connection handler)
1315
"""
1316
1317
if kb.passwordMgr and all(_ is not None for _ in (conf.scheme, conf.hostname, conf.port, conf.authUsername, conf.authPassword)):
1318
kb.passwordMgr.add_password(None, "%s://%s:%d" % (conf.scheme, conf.hostname, conf.port), conf.authUsername, conf.authPassword)
1319
1320
def _setHTTPAuthentication():
1321
"""
1322
Check and set the HTTP(s) authentication method (Basic, Digest, Bearer, NTLM or PKI),
1323
username and password for first three methods, or PEM private key file for
1324
PKI authentication
1325
"""
1326
1327
global authHandler
1328
1329
if not conf.authType and not conf.authCred and not conf.authFile:
1330
return
1331
1332
if conf.authFile and not conf.authType:
1333
conf.authType = AUTH_TYPE.PKI
1334
1335
elif conf.authType and not conf.authCred and not conf.authFile:
1336
errMsg = "you specified the HTTP authentication type, but "
1337
errMsg += "did not provide the credentials"
1338
raise SqlmapSyntaxException(errMsg)
1339
1340
elif not conf.authType and conf.authCred:
1341
errMsg = "you specified the HTTP authentication credentials, "
1342
errMsg += "but did not provide the type (e.g. --auth-type=\"basic\")"
1343
raise SqlmapSyntaxException(errMsg)
1344
1345
elif (conf.authType or "").lower() not in (AUTH_TYPE.BASIC, AUTH_TYPE.DIGEST, AUTH_TYPE.BEARER, AUTH_TYPE.NTLM, AUTH_TYPE.PKI):
1346
errMsg = "HTTP authentication type value must be "
1347
errMsg += "Basic, Digest, Bearer, NTLM or PKI"
1348
raise SqlmapSyntaxException(errMsg)
1349
1350
if not conf.authFile:
1351
debugMsg = "setting the HTTP authentication type and credentials"
1352
logger.debug(debugMsg)
1353
1354
authType = conf.authType.lower()
1355
1356
if authType in (AUTH_TYPE.BASIC, AUTH_TYPE.DIGEST):
1357
regExp = "^(.*?):(.*?)$"
1358
errMsg = "HTTP %s authentication credentials " % authType
1359
errMsg += "value must be in format 'username:password'"
1360
elif authType == AUTH_TYPE.BEARER:
1361
conf.httpHeaders.append((HTTP_HEADER.AUTHORIZATION, "Bearer %s" % conf.authCred.strip()))
1362
return
1363
elif authType == AUTH_TYPE.NTLM:
1364
regExp = "^(.*\\\\.*):(.*?)$"
1365
errMsg = "HTTP NTLM authentication credentials value must "
1366
errMsg += "be in format 'DOMAIN\\username:password'"
1367
elif authType == AUTH_TYPE.PKI:
1368
errMsg = "HTTP PKI authentication require "
1369
errMsg += "usage of option `--auth-file`"
1370
raise SqlmapSyntaxException(errMsg)
1371
1372
aCredRegExp = re.search(regExp, conf.authCred)
1373
1374
if not aCredRegExp:
1375
raise SqlmapSyntaxException(errMsg)
1376
1377
conf.authUsername = aCredRegExp.group(1)
1378
conf.authPassword = aCredRegExp.group(2)
1379
1380
kb.passwordMgr = _urllib.request.HTTPPasswordMgrWithDefaultRealm()
1381
1382
_setAuthCred()
1383
1384
if authType == AUTH_TYPE.BASIC:
1385
authHandler = SmartHTTPBasicAuthHandler(kb.passwordMgr)
1386
1387
elif authType == AUTH_TYPE.DIGEST:
1388
authHandler = _urllib.request.HTTPDigestAuthHandler(kb.passwordMgr)
1389
1390
elif authType == AUTH_TYPE.NTLM:
1391
try:
1392
from ntlm import HTTPNtlmAuthHandler
1393
except ImportError:
1394
errMsg = "sqlmap requires Python NTLM third-party library "
1395
errMsg += "in order to authenticate via NTLM. Download from "
1396
errMsg += "'https://github.com/mullender/python-ntlm'"
1397
raise SqlmapMissingDependence(errMsg)
1398
1399
authHandler = HTTPNtlmAuthHandler.HTTPNtlmAuthHandler(kb.passwordMgr)
1400
else:
1401
debugMsg = "setting the HTTP(s) authentication PEM private key"
1402
logger.debug(debugMsg)
1403
1404
_ = safeExpandUser(conf.authFile)
1405
checkFile(_)
1406
authHandler = HTTPSPKIAuthHandler(_)
1407
1408
def _setHTTPExtraHeaders():
1409
if conf.headers:
1410
debugMsg = "setting extra HTTP headers"
1411
logger.debug(debugMsg)
1412
1413
if "\\n" in conf.headers:
1414
conf.headers = conf.headers.replace("\\r\\n", "\\n").split("\\n")
1415
else:
1416
conf.headers = conf.headers.replace("\r\n", "\n").split("\n")
1417
1418
for headerValue in conf.headers:
1419
if not headerValue.strip():
1420
continue
1421
1422
if headerValue.count(':') >= 1:
1423
header, value = (_.lstrip() for _ in headerValue.split(":", 1))
1424
1425
if header and value:
1426
conf.httpHeaders.append((header, value))
1427
elif headerValue.startswith('@'):
1428
checkFile(headerValue[1:])
1429
kb.headersFile = headerValue[1:]
1430
else:
1431
errMsg = "invalid header value: %s. Valid header format is 'name:value'" % repr(headerValue).lstrip('u')
1432
raise SqlmapSyntaxException(errMsg)
1433
1434
elif not conf.requestFile and len(conf.httpHeaders or []) < 2:
1435
if conf.encoding:
1436
conf.httpHeaders.append((HTTP_HEADER.ACCEPT_CHARSET, "%s;q=0.7,*;q=0.1" % conf.encoding))
1437
1438
# Invalidating any caching mechanism in between
1439
# Reference: http://stackoverflow.com/a/1383359
1440
conf.httpHeaders.append((HTTP_HEADER.CACHE_CONTROL, "no-cache"))
1441
1442
def _setHTTPUserAgent():
1443
"""
1444
Set the HTTP User-Agent header.
1445
Depending on the user options it can be:
1446
1447
* The default sqlmap string
1448
* A default value read as user option
1449
* A random value read from a list of User-Agent headers from a
1450
file choosed as user option
1451
"""
1452
1453
debugMsg = "setting the HTTP User-Agent header"
1454
logger.debug(debugMsg)
1455
1456
if conf.mobile:
1457
if conf.randomAgent:
1458
_ = random.sample([_[1] for _ in getPublicTypeMembers(MOBILES, True)], 1)[0]
1459
conf.httpHeaders.append((HTTP_HEADER.USER_AGENT, _))
1460
else:
1461
message = "which smartphone do you want sqlmap to imitate "
1462
message += "through HTTP User-Agent header?\n"
1463
items = sorted(getPublicTypeMembers(MOBILES, True))
1464
1465
for count in xrange(len(items)):
1466
item = items[count]
1467
message += "[%d] %s%s\n" % (count + 1, item[0], " (default)" if item == MOBILES.IPHONE else "")
1468
1469
test = readInput(message.rstrip('\n'), default=items.index(MOBILES.IPHONE) + 1)
1470
1471
try:
1472
item = items[int(test) - 1]
1473
except:
1474
item = MOBILES.IPHONE
1475
1476
conf.httpHeaders.append((HTTP_HEADER.USER_AGENT, item[1]))
1477
1478
elif conf.agent:
1479
conf.httpHeaders.append((HTTP_HEADER.USER_AGENT, conf.agent))
1480
1481
elif not conf.randomAgent:
1482
_ = True
1483
1484
for header, _ in conf.httpHeaders:
1485
if header.upper() == HTTP_HEADER.USER_AGENT.upper():
1486
_ = False
1487
break
1488
1489
if _:
1490
conf.httpHeaders.append((HTTP_HEADER.USER_AGENT, DEFAULT_USER_AGENT))
1491
1492
else:
1493
userAgent = fetchRandomAgent()
1494
1495
infoMsg = "fetched random HTTP User-Agent header value '%s' from " % userAgent
1496
infoMsg += "file '%s'" % paths.USER_AGENTS
1497
logger.info(infoMsg)
1498
1499
conf.httpHeaders.append((HTTP_HEADER.USER_AGENT, userAgent))
1500
1501
def _setHTTPReferer():
1502
"""
1503
Set the HTTP Referer
1504
"""
1505
1506
if conf.referer:
1507
debugMsg = "setting the HTTP Referer header"
1508
logger.debug(debugMsg)
1509
1510
conf.httpHeaders.append((HTTP_HEADER.REFERER, conf.referer))
1511
1512
def _setHTTPHost():
1513
"""
1514
Set the HTTP Host
1515
"""
1516
1517
if conf.host:
1518
debugMsg = "setting the HTTP Host header"
1519
logger.debug(debugMsg)
1520
1521
conf.httpHeaders.append((HTTP_HEADER.HOST, conf.host))
1522
1523
def _setHTTPCookies():
1524
"""
1525
Set the HTTP Cookie header
1526
"""
1527
1528
if conf.cookie:
1529
debugMsg = "setting the HTTP Cookie header"
1530
logger.debug(debugMsg)
1531
1532
conf.httpHeaders.append((HTTP_HEADER.COOKIE, conf.cookie))
1533
1534
def _setHostname():
1535
"""
1536
Set value conf.hostname
1537
"""
1538
1539
if conf.url:
1540
try:
1541
conf.hostname = _urllib.parse.urlsplit(conf.url).netloc.split(':')[0]
1542
except ValueError as ex:
1543
errMsg = "problem occurred while "
1544
errMsg += "parsing an URL '%s' ('%s')" % (conf.url, getSafeExString(ex))
1545
raise SqlmapDataException(errMsg)
1546
1547
def _setHTTPTimeout():
1548
"""
1549
Set the HTTP timeout
1550
"""
1551
1552
if conf.timeout:
1553
debugMsg = "setting the HTTP timeout"
1554
logger.debug(debugMsg)
1555
1556
conf.timeout = float(conf.timeout)
1557
1558
if conf.timeout < 3.0:
1559
warnMsg = "the minimum HTTP timeout is 3 seconds, sqlmap "
1560
warnMsg += "will going to reset it"
1561
logger.warning(warnMsg)
1562
1563
conf.timeout = 3.0
1564
else:
1565
conf.timeout = 30.0
1566
1567
try:
1568
socket.setdefaulttimeout(conf.timeout)
1569
except OverflowError as ex:
1570
raise SqlmapValueException("invalid value used for option '--timeout' ('%s')" % getSafeExString(ex))
1571
1572
def _checkDependencies():
1573
"""
1574
Checks for missing dependencies.
1575
"""
1576
1577
if conf.dependencies:
1578
checkDependencies()
1579
1580
def _createHomeDirectories():
1581
"""
1582
Creates directories inside sqlmap's home directory
1583
"""
1584
1585
if conf.get("purge"):
1586
return
1587
1588
for context in ("output", "history"):
1589
directory = paths["SQLMAP_%s_PATH" % getUnicode(context).upper()] # NOTE: https://github.com/sqlmapproject/sqlmap/issues/4363
1590
try:
1591
if not os.path.isdir(directory):
1592
os.makedirs(directory)
1593
1594
_ = os.path.join(directory, randomStr())
1595
open(_, "w+b").close()
1596
os.remove(_)
1597
1598
if conf.get("outputDir") and context == "output":
1599
warnMsg = "using '%s' as the %s directory" % (directory, context)
1600
logger.warning(warnMsg)
1601
except (OSError, IOError) as ex:
1602
tempDir = tempfile.mkdtemp(prefix="sqlmap%s" % context)
1603
warnMsg = "unable to %s %s directory " % ("create" if not os.path.isdir(directory) else "write to the", context)
1604
warnMsg += "'%s' (%s). " % (directory, getUnicode(ex))
1605
warnMsg += "Using temporary directory '%s' instead" % getUnicode(tempDir)
1606
logger.warning(warnMsg)
1607
1608
paths["SQLMAP_%s_PATH" % context.upper()] = tempDir
1609
1610
def _pympTempLeakPatch(tempDir): # Cross-referenced function
1611
raise NotImplementedError
1612
1613
def _createTemporaryDirectory():
1614
"""
1615
Creates temporary directory for this run.
1616
"""
1617
1618
if conf.tmpDir:
1619
try:
1620
if not os.path.isdir(conf.tmpDir):
1621
os.makedirs(conf.tmpDir)
1622
1623
_ = os.path.join(conf.tmpDir, randomStr())
1624
1625
open(_, "w+b").close()
1626
os.remove(_)
1627
1628
tempfile.tempdir = conf.tmpDir
1629
1630
warnMsg = "using '%s' as the temporary directory" % conf.tmpDir
1631
logger.warning(warnMsg)
1632
except (OSError, IOError) as ex:
1633
errMsg = "there has been a problem while accessing "
1634
errMsg += "temporary directory location(s) ('%s')" % getSafeExString(ex)
1635
raise SqlmapSystemException(errMsg)
1636
else:
1637
try:
1638
if not os.path.isdir(tempfile.gettempdir()):
1639
os.makedirs(tempfile.gettempdir())
1640
except Exception as ex:
1641
warnMsg = "there has been a problem while accessing "
1642
warnMsg += "system's temporary directory location(s) ('%s'). Please " % getSafeExString(ex)
1643
warnMsg += "make sure that there is enough disk space left. If problem persists, "
1644
warnMsg += "try to set environment variable 'TEMP' to a location "
1645
warnMsg += "writeable by the current user"
1646
logger.warning(warnMsg)
1647
1648
if "sqlmap" not in (tempfile.tempdir or "") or conf.tmpDir and tempfile.tempdir == conf.tmpDir:
1649
try:
1650
tempfile.tempdir = tempfile.mkdtemp(prefix="sqlmap", suffix=str(os.getpid()))
1651
except:
1652
tempfile.tempdir = os.path.join(paths.SQLMAP_HOME_PATH, "tmp", "sqlmap%s%d" % (randomStr(6), os.getpid()))
1653
1654
kb.tempDir = tempfile.tempdir
1655
1656
if not os.path.isdir(tempfile.tempdir):
1657
try:
1658
os.makedirs(tempfile.tempdir)
1659
except Exception as ex:
1660
errMsg = "there has been a problem while setting "
1661
errMsg += "temporary directory location ('%s')" % getSafeExString(ex)
1662
raise SqlmapSystemException(errMsg)
1663
1664
conf.tempDirs.append(tempfile.tempdir)
1665
1666
if six.PY3:
1667
_pympTempLeakPatch(kb.tempDir)
1668
1669
def _cleanupOptions():
1670
"""
1671
Cleanup configuration attributes.
1672
"""
1673
1674
if conf.encoding:
1675
try:
1676
codecs.lookup(conf.encoding)
1677
except LookupError:
1678
errMsg = "unknown encoding '%s'" % conf.encoding
1679
raise SqlmapValueException(errMsg)
1680
1681
debugMsg = "cleaning up configuration parameters"
1682
logger.debug(debugMsg)
1683
1684
width = getConsoleWidth()
1685
1686
if conf.eta:
1687
conf.progressWidth = width - 26
1688
else:
1689
conf.progressWidth = width - 46
1690
1691
for key, value in conf.items():
1692
if value and any(key.endswith(_) for _ in ("Path", "File", "Dir")):
1693
if isinstance(value, str):
1694
conf[key] = safeExpandUser(value)
1695
1696
if conf.testParameter:
1697
conf.testParameter = urldecode(conf.testParameter)
1698
conf.testParameter = [_.strip() for _ in re.split(PARAMETER_SPLITTING_REGEX, conf.testParameter)]
1699
else:
1700
conf.testParameter = []
1701
1702
if conf.ignoreCode:
1703
if conf.ignoreCode == IGNORE_CODE_WILDCARD:
1704
conf.ignoreCode = xrange(0, 1000)
1705
else:
1706
try:
1707
conf.ignoreCode = [int(_) for _ in re.split(PARAMETER_SPLITTING_REGEX, conf.ignoreCode)]
1708
except ValueError:
1709
errMsg = "option '--ignore-code' should contain a list of integer values or a wildcard value '%s'" % IGNORE_CODE_WILDCARD
1710
raise SqlmapSyntaxException(errMsg)
1711
else:
1712
conf.ignoreCode = []
1713
1714
if conf.abortCode:
1715
try:
1716
conf.abortCode = [int(_) for _ in re.split(PARAMETER_SPLITTING_REGEX, conf.abortCode)]
1717
except ValueError:
1718
errMsg = "option '--abort-code' should contain a list of integer values"
1719
raise SqlmapSyntaxException(errMsg)
1720
else:
1721
conf.abortCode = []
1722
1723
if conf.paramFilter:
1724
conf.paramFilter = [_.strip() for _ in re.split(PARAMETER_SPLITTING_REGEX, conf.paramFilter.upper())]
1725
else:
1726
conf.paramFilter = []
1727
1728
if conf.base64Parameter:
1729
conf.base64Parameter = urldecode(conf.base64Parameter)
1730
conf.base64Parameter = conf.base64Parameter.strip()
1731
conf.base64Parameter = re.split(PARAMETER_SPLITTING_REGEX, conf.base64Parameter)
1732
else:
1733
conf.base64Parameter = []
1734
1735
if conf.agent:
1736
conf.agent = re.sub(r"[\r\n]", "", conf.agent)
1737
1738
if conf.user:
1739
conf.user = conf.user.replace(" ", "")
1740
1741
if conf.rParam:
1742
if all(_ in conf.rParam for _ in ('=', ',')):
1743
original = conf.rParam
1744
conf.rParam = []
1745
for part in original.split(';'):
1746
if '=' in part:
1747
left, right = part.split('=', 1)
1748
conf.rParam.append(left)
1749
kb.randomPool[left] = filterNone(_.strip() for _ in right.split(','))
1750
else:
1751
conf.rParam.append(part)
1752
else:
1753
conf.rParam = conf.rParam.replace(" ", "")
1754
conf.rParam = re.split(PARAMETER_SPLITTING_REGEX, conf.rParam)
1755
else:
1756
conf.rParam = []
1757
1758
if conf.paramDel:
1759
conf.paramDel = decodeStringEscape(conf.paramDel)
1760
1761
if conf.skip:
1762
conf.skip = conf.skip.replace(" ", "")
1763
conf.skip = re.split(PARAMETER_SPLITTING_REGEX, conf.skip)
1764
else:
1765
conf.skip = []
1766
1767
if conf.cookie:
1768
conf.cookie = re.sub(r"[\r\n]", "", conf.cookie)
1769
1770
if conf.delay:
1771
conf.delay = float(conf.delay)
1772
1773
if conf.url:
1774
conf.url = conf.url.strip().lstrip('/')
1775
if not re.search(r"\A\w+://", conf.url):
1776
conf.url = "http://%s" % conf.url
1777
1778
if conf.fileRead:
1779
conf.fileRead = ntToPosixSlashes(normalizePath(conf.fileRead))
1780
1781
if conf.fileWrite:
1782
conf.fileWrite = ntToPosixSlashes(normalizePath(conf.fileWrite))
1783
1784
if conf.fileDest:
1785
conf.fileDest = ntToPosixSlashes(normalizePath(conf.fileDest))
1786
1787
if conf.msfPath:
1788
conf.msfPath = ntToPosixSlashes(normalizePath(conf.msfPath))
1789
1790
if conf.tmpPath:
1791
conf.tmpPath = ntToPosixSlashes(normalizePath(conf.tmpPath))
1792
1793
if any((conf.googleDork, conf.logFile, conf.bulkFile, conf.forms, conf.crawlDepth, conf.stdinPipe)):
1794
conf.multipleTargets = True
1795
1796
if conf.optimize:
1797
setOptimize()
1798
1799
if conf.os:
1800
conf.os = conf.os.capitalize()
1801
1802
if conf.forceDbms:
1803
conf.dbms = conf.forceDbms
1804
1805
if conf.dbms:
1806
kb.dbmsFilter = []
1807
for _ in conf.dbms.split(','):
1808
for dbms, aliases in DBMS_ALIASES:
1809
if _.strip().lower() in aliases:
1810
kb.dbmsFilter.append(dbms)
1811
conf.dbms = dbms if conf.dbms and ',' not in conf.dbms else None
1812
break
1813
1814
if conf.uValues:
1815
conf.uCols = "%d-%d" % (1 + conf.uValues.count(','), 1 + conf.uValues.count(','))
1816
1817
if conf.testFilter:
1818
conf.testFilter = conf.testFilter.strip('*+')
1819
conf.testFilter = re.sub(r"([^.])([*+])", r"\g<1>.\g<2>", conf.testFilter)
1820
1821
try:
1822
re.compile(conf.testFilter)
1823
except re.error:
1824
conf.testFilter = re.escape(conf.testFilter)
1825
1826
if conf.csrfToken:
1827
original = conf.csrfToken
1828
try:
1829
re.compile(conf.csrfToken)
1830
1831
if re.escape(conf.csrfToken) != conf.csrfToken:
1832
message = "provided value for option '--csrf-token' is a regular expression? [y/N] "
1833
if not readInput(message, default='N', boolean=True):
1834
conf.csrfToken = re.escape(conf.csrfToken)
1835
except re.error:
1836
conf.csrfToken = re.escape(conf.csrfToken)
1837
finally:
1838
class _(six.text_type):
1839
pass
1840
conf.csrfToken = _(conf.csrfToken)
1841
conf.csrfToken._original = original
1842
1843
if conf.testSkip:
1844
conf.testSkip = conf.testSkip.strip('*+')
1845
conf.testSkip = re.sub(r"([^.])([*+])", r"\g<1>.\g<2>", conf.testSkip)
1846
1847
try:
1848
re.compile(conf.testSkip)
1849
except re.error:
1850
conf.testSkip = re.escape(conf.testSkip)
1851
1852
if "timeSec" not in kb.explicitSettings:
1853
if conf.tor:
1854
conf.timeSec = 2 * conf.timeSec
1855
kb.adjustTimeDelay = ADJUST_TIME_DELAY.DISABLE
1856
1857
warnMsg = "increasing default value for "
1858
warnMsg += "option '--time-sec' to %d because " % conf.timeSec
1859
warnMsg += "switch '--tor' was provided"
1860
logger.warning(warnMsg)
1861
else:
1862
kb.adjustTimeDelay = ADJUST_TIME_DELAY.DISABLE
1863
1864
if conf.retries:
1865
conf.retries = min(conf.retries, MAX_CONNECT_RETRIES)
1866
1867
if conf.url:
1868
match = re.search(r"\A(\w+://)?([^/@?]+)@", conf.url)
1869
if match:
1870
credentials = match.group(2)
1871
conf.url = conf.url.replace("%s@" % credentials, "", 1)
1872
1873
conf.authType = AUTH_TYPE.BASIC
1874
conf.authCred = credentials if ':' in credentials else "%s:" % credentials
1875
1876
if conf.code:
1877
conf.code = int(conf.code)
1878
1879
if conf.csvDel:
1880
conf.csvDel = decodeStringEscape(conf.csvDel)
1881
1882
if conf.torPort and hasattr(conf.torPort, "isdigit") and conf.torPort.isdigit():
1883
conf.torPort = int(conf.torPort)
1884
1885
if conf.torType:
1886
conf.torType = conf.torType.upper()
1887
1888
if conf.outputDir:
1889
paths.SQLMAP_OUTPUT_PATH = os.path.realpath(os.path.expanduser(conf.outputDir))
1890
setPaths(paths.SQLMAP_ROOT_PATH)
1891
1892
if conf.string:
1893
conf.string = decodeStringEscape(conf.string)
1894
1895
if conf.getAll:
1896
for _ in WIZARD.ALL:
1897
conf.__setitem__(_, True)
1898
1899
if conf.noCast:
1900
DUMP_REPLACEMENTS.clear()
1901
1902
if conf.dumpFormat:
1903
conf.dumpFormat = conf.dumpFormat.upper()
1904
1905
if conf.torType:
1906
conf.torType = conf.torType.upper()
1907
1908
if conf.col:
1909
conf.col = re.sub(r"\s*,\s*", ',', conf.col)
1910
1911
if conf.exclude:
1912
regex = False
1913
original = conf.exclude
1914
1915
if any(_ in conf.exclude for _ in ('+', '*')):
1916
try:
1917
re.compile(conf.exclude)
1918
except re.error:
1919
pass
1920
else:
1921
regex = True
1922
1923
if not regex:
1924
conf.exclude = re.sub(r"\s*,\s*", ',', conf.exclude)
1925
conf.exclude = r"\A%s\Z" % '|'.join(re.escape(_) for _ in conf.exclude.split(','))
1926
else:
1927
conf.exclude = re.sub(r"(\w+)\$", r"\g<1>\$", conf.exclude)
1928
1929
class _(six.text_type):
1930
pass
1931
1932
conf.exclude = _(conf.exclude)
1933
conf.exclude._original = original
1934
1935
if conf.binaryFields:
1936
conf.binaryFields = conf.binaryFields.replace(" ", "")
1937
conf.binaryFields = re.split(PARAMETER_SPLITTING_REGEX, conf.binaryFields)
1938
1939
envProxy = max(os.environ.get(_, "") for _ in PROXY_ENVIRONMENT_VARIABLES)
1940
if re.search(r"\A(https?|socks[45])://.+:\d+\Z", envProxy) and conf.proxy is None:
1941
debugMsg = "using environment proxy '%s'" % envProxy
1942
logger.debug(debugMsg)
1943
1944
conf.proxy = envProxy
1945
1946
if any((conf.proxy, conf.proxyFile, conf.tor)):
1947
conf.disablePrecon = True
1948
1949
if conf.dummy:
1950
conf.batch = True
1951
1952
threadData = getCurrentThreadData()
1953
threadData.reset()
1954
1955
def _cleanupEnvironment():
1956
"""
1957
Cleanup environment (e.g. from leftovers after --shell).
1958
"""
1959
1960
if issubclass(_http_client.socket.socket, socks.socksocket):
1961
socks.unwrapmodule(_http_client)
1962
1963
if hasattr(socket, "_ready"):
1964
socket._ready.clear()
1965
1966
def _purge():
1967
"""
1968
Safely removes (purges) sqlmap data directory.
1969
"""
1970
1971
if conf.purge:
1972
purge(paths.SQLMAP_HOME_PATH)
1973
1974
def _setConfAttributes():
1975
"""
1976
This function set some needed attributes into the configuration
1977
singleton.
1978
"""
1979
1980
debugMsg = "initializing the configuration"
1981
logger.debug(debugMsg)
1982
1983
conf.authUsername = None
1984
conf.authPassword = None
1985
conf.boundaries = []
1986
conf.cj = None
1987
conf.dbmsConnector = None
1988
conf.dbmsHandler = None
1989
conf.dnsServer = None
1990
conf.dumpPath = None
1991
conf.fileWriteType = None
1992
conf.HARCollectorFactory = None
1993
conf.hashDB = None
1994
conf.hashDBFile = None
1995
conf.httpCollector = None
1996
conf.httpHeaders = []
1997
conf.hostname = None
1998
conf.ipv6 = False
1999
conf.multipleTargets = False
2000
conf.outputPath = None
2001
conf.paramDict = {}
2002
conf.parameters = {}
2003
conf.path = None
2004
conf.port = None
2005
conf.proxyList = None
2006
conf.resultsFP = None
2007
conf.scheme = None
2008
conf.tests = []
2009
conf.tempDirs = []
2010
conf.trafficFP = None
2011
2012
def _setKnowledgeBaseAttributes(flushAll=True):
2013
"""
2014
This function set some needed attributes into the knowledge base
2015
singleton.
2016
"""
2017
2018
debugMsg = "initializing the knowledge base"
2019
logger.debug(debugMsg)
2020
2021
kb.absFilePaths = set()
2022
kb.adjustTimeDelay = None
2023
kb.alerted = False
2024
kb.aliasName = randomStr()
2025
kb.alwaysRefresh = None
2026
kb.arch = None
2027
kb.authHeader = None
2028
kb.bannerFp = AttribDict()
2029
kb.base64Originals = {}
2030
kb.binaryField = False
2031
kb.browserVerification = None
2032
2033
kb.brute = AttribDict({"tables": [], "columns": []})
2034
kb.bruteMode = False
2035
2036
kb.cache = AttribDict()
2037
kb.cache.addrinfo = {}
2038
kb.cache.content = {}
2039
kb.cache.comparison = {}
2040
kb.cache.encoding = {}
2041
kb.cache.alphaBoundaries = None
2042
kb.cache.hashRegex = None
2043
kb.cache.intBoundaries = None
2044
kb.cache.parsedDbms = {}
2045
kb.cache.regex = {}
2046
kb.cache.stdev = {}
2047
2048
kb.captchaDetected = None
2049
2050
kb.chars = AttribDict()
2051
kb.chars.delimiter = randomStr(length=6, lowercase=True)
2052
kb.chars.start = "%s%s%s" % (KB_CHARS_BOUNDARY_CHAR, randomStr(length=3, alphabet=KB_CHARS_LOW_FREQUENCY_ALPHABET), KB_CHARS_BOUNDARY_CHAR)
2053
kb.chars.stop = "%s%s%s" % (KB_CHARS_BOUNDARY_CHAR, randomStr(length=3, alphabet=KB_CHARS_LOW_FREQUENCY_ALPHABET), KB_CHARS_BOUNDARY_CHAR)
2054
kb.chars.at, kb.chars.space, kb.chars.dollar, kb.chars.hash_ = ("%s%s%s" % (KB_CHARS_BOUNDARY_CHAR, _, KB_CHARS_BOUNDARY_CHAR) for _ in randomStr(length=4, lowercase=True))
2055
2056
kb.choices = AttribDict(keycheck=False)
2057
kb.codePage = None
2058
kb.commonOutputs = None
2059
kb.connErrorCounter = 0
2060
kb.copyExecTest = None
2061
kb.counters = {}
2062
kb.customInjectionMark = CUSTOM_INJECTION_MARK_CHAR
2063
kb.data = AttribDict()
2064
kb.dataOutputFlag = False
2065
2066
# Active back-end DBMS fingerprint
2067
kb.dbms = None
2068
kb.dbmsFilter = []
2069
kb.dbmsVersion = [UNKNOWN_DBMS_VERSION]
2070
2071
kb.delayCandidates = TIME_DELAY_CANDIDATES * [0]
2072
kb.dep = None
2073
kb.disableHtmlDecoding = False
2074
kb.disableShiftTable = False
2075
kb.dnsMode = False
2076
kb.dnsTest = None
2077
kb.docRoot = None
2078
kb.droppingRequests = False
2079
kb.dumpColumns = None
2080
kb.dumpTable = None
2081
kb.dumpKeyboardInterrupt = False
2082
kb.dynamicMarkings = []
2083
kb.dynamicParameter = False
2084
kb.endDetection = False
2085
kb.explicitSettings = set()
2086
kb.extendTests = None
2087
kb.errorChunkLength = None
2088
kb.errorIsNone = True
2089
kb.falsePositives = []
2090
kb.fileReadMode = False
2091
kb.fingerprinted = False
2092
kb.followSitemapRecursion = None
2093
kb.forcedDbms = None
2094
kb.forcePartialUnion = False
2095
kb.forceThreads = None
2096
kb.forceWhere = None
2097
kb.forkNote = None
2098
kb.futileUnion = None
2099
kb.fuzzUnionTest = None
2100
kb.heavilyDynamic = False
2101
kb.headersFile = None
2102
kb.headersFp = {}
2103
kb.heuristicDbms = None
2104
kb.heuristicExtendedDbms = None
2105
kb.heuristicCode = None
2106
kb.heuristicMode = False
2107
kb.heuristicPage = False
2108
kb.heuristicTest = None
2109
kb.hintValue = ""
2110
kb.htmlFp = []
2111
kb.httpErrorCodes = {}
2112
kb.inferenceMode = False
2113
kb.ignoreCasted = None
2114
kb.ignoreNotFound = False
2115
kb.ignoreTimeout = False
2116
kb.identifiedWafs = set()
2117
kb.injection = InjectionDict()
2118
kb.injections = []
2119
kb.jsonAggMode = False
2120
kb.laggingChecked = False
2121
kb.lastParserStatus = None
2122
2123
kb.locks = AttribDict()
2124
for _ in ("cache", "connError", "count", "handlers", "hint", "identYwaf", "index", "io", "limit", "liveCookies", "log", "socket", "redirect", "request", "value"):
2125
kb.locks[_] = threading.Lock()
2126
2127
kb.matchRatio = None
2128
kb.maxConnectionsFlag = False
2129
kb.mergeCookies = None
2130
kb.multiThreadMode = False
2131
kb.multipleCtrlC = False
2132
kb.negativeLogic = False
2133
kb.nchar = True
2134
kb.nullConnection = None
2135
kb.oldMsf = None
2136
kb.orderByColumns = None
2137
kb.originalCode = None
2138
kb.originalPage = None
2139
kb.originalPageTime = None
2140
kb.originalTimeDelay = None
2141
kb.originalUrls = dict()
2142
2143
# Back-end DBMS underlying operating system fingerprint via banner (-b)
2144
# parsing
2145
kb.os = None
2146
kb.osVersion = None
2147
kb.osSP = None
2148
2149
kb.pageCompress = True
2150
kb.pageTemplate = None
2151
kb.pageTemplates = dict()
2152
kb.pageEncoding = DEFAULT_PAGE_ENCODING
2153
kb.pageStable = None
2154
kb.partRun = None
2155
kb.permissionFlag = False
2156
kb.place = None
2157
kb.postHint = None
2158
kb.postSpaceToPlus = False
2159
kb.postUrlEncode = True
2160
kb.prependFlag = False
2161
kb.processResponseCounter = 0
2162
kb.previousMethod = None
2163
kb.processNonCustom = None
2164
kb.processUserMarks = None
2165
kb.proxies = None
2166
kb.proxyAuthHeader = None
2167
kb.queryCounter = 0
2168
kb.randomPool = {}
2169
kb.reflectiveMechanism = True
2170
kb.reflectiveCounters = {REFLECTIVE_COUNTER.MISS: 0, REFLECTIVE_COUNTER.HIT: 0}
2171
kb.requestCounter = 0
2172
kb.resendPostOnRedirect = None
2173
kb.resolutionDbms = None
2174
kb.responseTimes = {}
2175
kb.responseTimeMode = None
2176
kb.responseTimePayload = None
2177
kb.resumeValues = True
2178
kb.safeCharEncode = False
2179
kb.safeReq = AttribDict()
2180
kb.secondReq = None
2181
kb.serverHeader = None
2182
kb.singleLogFlags = set()
2183
kb.skipSeqMatcher = False
2184
kb.smokeMode = False
2185
kb.reduceTests = None
2186
kb.sslSuccess = False
2187
kb.startTime = time.time()
2188
kb.stickyDBMS = False
2189
kb.suppressResumeInfo = False
2190
kb.tableFrom = None
2191
kb.technique = None
2192
kb.tempDir = None
2193
kb.testMode = False
2194
kb.testOnlyCustom = False
2195
kb.testQueryCount = 0
2196
kb.testType = None
2197
kb.threadContinue = True
2198
kb.threadException = False
2199
kb.uChar = NULL
2200
kb.udfFail = False
2201
kb.unionDuplicates = False
2202
kb.unionTemplate = None
2203
kb.webSocketRecvCount = None
2204
kb.wizardMode = False
2205
kb.xpCmdshellAvailable = False
2206
2207
if flushAll:
2208
kb.checkSitemap = None
2209
kb.headerPaths = {}
2210
kb.keywords = set(getFileItems(paths.SQL_KEYWORDS))
2211
kb.lastCtrlCTime = None
2212
kb.normalizeCrawlingChoice = None
2213
kb.passwordMgr = None
2214
kb.postprocessFunctions = []
2215
kb.preprocessFunctions = []
2216
kb.skipVulnHost = None
2217
kb.storeCrawlingChoice = None
2218
kb.tamperFunctions = []
2219
kb.targets = OrderedSet()
2220
kb.testedParams = set()
2221
kb.userAgents = None
2222
kb.vainRun = True
2223
kb.vulnHosts = set()
2224
kb.wafFunctions = []
2225
kb.wordlists = None
2226
2227
def _useWizardInterface():
2228
"""
2229
Presents simple wizard interface for beginner users
2230
"""
2231
2232
if not conf.wizard:
2233
return
2234
2235
logger.info("starting wizard interface")
2236
2237
while not conf.url:
2238
message = "Please enter full target URL (-u): "
2239
conf.url = readInput(message, default=None, checkBatch=False)
2240
2241
message = "%s data (--data) [Enter for None]: " % ((conf.method if conf.method != HTTPMETHOD.GET else None) or HTTPMETHOD.POST)
2242
conf.data = readInput(message, default=None)
2243
2244
if not (any('=' in _ for _ in (conf.url, conf.data)) or '*' in conf.url):
2245
warnMsg = "no GET and/or %s parameter(s) found for testing " % ((conf.method if conf.method != HTTPMETHOD.GET else None) or HTTPMETHOD.POST)
2246
warnMsg += "(e.g. GET parameter 'id' in 'http://www.site.com/vuln.php?id=1'). "
2247
if not conf.crawlDepth and not conf.forms:
2248
warnMsg += "Will search for forms"
2249
conf.forms = True
2250
logger.warning(warnMsg)
2251
2252
choice = None
2253
2254
while choice is None or choice not in ("", "1", "2", "3"):
2255
message = "Injection difficulty (--level/--risk). Please choose:\n"
2256
message += "[1] Normal (default)\n[2] Medium\n[3] Hard"
2257
choice = readInput(message, default='1')
2258
2259
if choice == '2':
2260
conf.risk = 2
2261
conf.level = 3
2262
elif choice == '3':
2263
conf.risk = 3
2264
conf.level = 5
2265
else:
2266
conf.risk = 1
2267
conf.level = 1
2268
2269
if not conf.getAll:
2270
choice = None
2271
2272
while choice is None or choice not in ("", "1", "2", "3"):
2273
message = "Enumeration (--banner/--current-user/etc). Please choose:\n"
2274
message += "[1] Basic (default)\n[2] Intermediate\n[3] All"
2275
choice = readInput(message, default='1')
2276
2277
if choice == '2':
2278
options = WIZARD.INTERMEDIATE
2279
elif choice == '3':
2280
options = WIZARD.ALL
2281
else:
2282
options = WIZARD.BASIC
2283
2284
for _ in options:
2285
conf.__setitem__(_, True)
2286
2287
logger.debug("muting sqlmap.. it will do the magic for you")
2288
conf.verbose = 0
2289
2290
conf.batch = True
2291
conf.threads = 4
2292
2293
dataToStdout("\nsqlmap is running, please wait..\n\n")
2294
2295
kb.wizardMode = True
2296
2297
def _saveConfig():
2298
"""
2299
Saves the command line options to a sqlmap configuration INI file
2300
Format.
2301
"""
2302
2303
if not conf.saveConfig:
2304
return
2305
2306
debugMsg = "saving command line options to a sqlmap configuration INI file"
2307
logger.debug(debugMsg)
2308
2309
saveConfig(conf, conf.saveConfig)
2310
2311
infoMsg = "saved command line options to the configuration file '%s'" % conf.saveConfig
2312
logger.info(infoMsg)
2313
2314
def setVerbosity():
2315
"""
2316
This function set the verbosity of sqlmap output messages.
2317
"""
2318
2319
if conf.verbose is None:
2320
conf.verbose = 1
2321
2322
conf.verbose = int(conf.verbose)
2323
2324
if conf.verbose == 0:
2325
logger.setLevel(logging.ERROR)
2326
elif conf.verbose == 1:
2327
logger.setLevel(logging.INFO)
2328
elif conf.verbose > 2 and conf.eta:
2329
conf.verbose = 2
2330
logger.setLevel(logging.DEBUG)
2331
elif conf.verbose == 2:
2332
logger.setLevel(logging.DEBUG)
2333
elif conf.verbose == 3:
2334
logger.setLevel(CUSTOM_LOGGING.PAYLOAD)
2335
elif conf.verbose == 4:
2336
logger.setLevel(CUSTOM_LOGGING.TRAFFIC_OUT)
2337
elif conf.verbose >= 5:
2338
logger.setLevel(CUSTOM_LOGGING.TRAFFIC_IN)
2339
2340
def _normalizeOptions(inputOptions):
2341
"""
2342
Sets proper option types
2343
"""
2344
2345
types_ = {}
2346
for group in optDict.keys():
2347
types_.update(optDict[group])
2348
2349
for key in inputOptions:
2350
if key in types_:
2351
value = inputOptions[key]
2352
if value is None:
2353
continue
2354
2355
type_ = types_[key]
2356
if type_ and isinstance(type_, tuple):
2357
type_ = type_[0]
2358
2359
if type_ == OPTION_TYPE.BOOLEAN:
2360
try:
2361
value = bool(value)
2362
except (TypeError, ValueError):
2363
value = False
2364
elif type_ == OPTION_TYPE.INTEGER:
2365
try:
2366
value = int(value)
2367
except (TypeError, ValueError):
2368
value = 0
2369
elif type_ == OPTION_TYPE.FLOAT:
2370
try:
2371
value = float(value)
2372
except (TypeError, ValueError):
2373
value = 0.0
2374
2375
inputOptions[key] = value
2376
2377
def _mergeOptions(inputOptions, overrideOptions):
2378
"""
2379
Merge command line options with configuration file and default options.
2380
2381
@param inputOptions: optparse object with command line options.
2382
@type inputOptions: C{instance}
2383
"""
2384
2385
if inputOptions.configFile:
2386
configFileParser(inputOptions.configFile)
2387
2388
if hasattr(inputOptions, "items"):
2389
inputOptionsItems = inputOptions.items()
2390
else:
2391
inputOptionsItems = inputOptions.__dict__.items()
2392
2393
for key, value in inputOptionsItems:
2394
if key not in conf or value not in (None, False) or overrideOptions:
2395
conf[key] = value
2396
2397
if not conf.api:
2398
for key, value in conf.items():
2399
if value is not None:
2400
kb.explicitSettings.add(key)
2401
2402
for key, value in defaults.items():
2403
if hasattr(conf, key) and conf[key] is None:
2404
conf[key] = value
2405
2406
if conf.unstable:
2407
if key in ("timeSec", "retries", "timeout"):
2408
conf[key] *= 2
2409
2410
if conf.unstable:
2411
conf.forcePartial = True
2412
2413
lut = {}
2414
for group in optDict.keys():
2415
lut.update((_.upper(), _) for _ in optDict[group])
2416
2417
envOptions = {}
2418
for key, value in os.environ.items():
2419
if key.upper().startswith(SQLMAP_ENVIRONMENT_PREFIX):
2420
_ = key[len(SQLMAP_ENVIRONMENT_PREFIX):].upper()
2421
if _ in lut:
2422
envOptions[lut[_]] = value
2423
2424
if envOptions:
2425
_normalizeOptions(envOptions)
2426
for key, value in envOptions.items():
2427
conf[key] = value
2428
2429
mergedOptions.update(conf)
2430
2431
def _setTrafficOutputFP():
2432
if conf.trafficFile:
2433
infoMsg = "setting file for logging HTTP traffic"
2434
logger.info(infoMsg)
2435
2436
conf.trafficFP = openFile(conf.trafficFile, "w+")
2437
2438
def _setupHTTPCollector():
2439
if not conf.harFile:
2440
return
2441
2442
conf.httpCollector = HTTPCollectorFactory(conf.harFile).create()
2443
2444
def _setDNSServer():
2445
if not conf.dnsDomain:
2446
return
2447
2448
infoMsg = "setting up DNS server instance"
2449
logger.info(infoMsg)
2450
2451
isAdmin = runningAsAdmin()
2452
2453
if isAdmin:
2454
try:
2455
conf.dnsServer = DNSServer()
2456
conf.dnsServer.run()
2457
except socket.error as ex:
2458
errMsg = "there was an error while setting up "
2459
errMsg += "DNS server instance ('%s')" % getSafeExString(ex)
2460
raise SqlmapGenericException(errMsg)
2461
else:
2462
errMsg = "you need to run sqlmap as an administrator "
2463
errMsg += "if you want to perform a DNS data exfiltration attack "
2464
errMsg += "as it will need to listen on privileged UDP port 53 "
2465
errMsg += "for incoming address resolution attempts"
2466
raise SqlmapMissingPrivileges(errMsg)
2467
2468
def _setProxyList():
2469
if not conf.proxyFile:
2470
return
2471
2472
conf.proxyList = []
2473
for match in re.finditer(r"(?i)((http[^:]*|socks[^:]*)://)?([\w\-.]+):(\d+)", readCachedFileContent(conf.proxyFile)):
2474
_, type_, address, port = match.groups()
2475
conf.proxyList.append("%s://%s:%s" % (type_ or "http", address, port))
2476
2477
def _setTorProxySettings():
2478
if not conf.tor:
2479
return
2480
2481
if conf.torType == PROXY_TYPE.HTTP:
2482
_setTorHttpProxySettings()
2483
else:
2484
_setTorSocksProxySettings()
2485
2486
def _setTorHttpProxySettings():
2487
infoMsg = "setting Tor HTTP proxy settings"
2488
logger.info(infoMsg)
2489
2490
port = findLocalPort(DEFAULT_TOR_HTTP_PORTS if not conf.torPort else (conf.torPort,))
2491
2492
if port:
2493
conf.proxy = "http://%s:%d" % (LOCALHOST, port)
2494
else:
2495
errMsg = "can't establish connection with the Tor HTTP proxy. "
2496
errMsg += "Please make sure that you have Tor (bundle) installed and setup "
2497
errMsg += "so you could be able to successfully use switch '--tor' "
2498
raise SqlmapConnectionException(errMsg)
2499
2500
if not conf.checkTor:
2501
warnMsg = "use switch '--check-tor' at "
2502
warnMsg += "your own convenience when accessing "
2503
warnMsg += "Tor anonymizing network because of "
2504
warnMsg += "known issues with default settings of various 'bundles' "
2505
warnMsg += "(e.g. Vidalia)"
2506
logger.warning(warnMsg)
2507
2508
def _setTorSocksProxySettings():
2509
infoMsg = "setting Tor SOCKS proxy settings"
2510
logger.info(infoMsg)
2511
2512
port = findLocalPort(DEFAULT_TOR_SOCKS_PORTS if not conf.torPort else (conf.torPort,))
2513
2514
if not port:
2515
errMsg = "can't establish connection with the Tor SOCKS proxy. "
2516
errMsg += "Please make sure that you have Tor service installed and setup "
2517
errMsg += "so you could be able to successfully use switch '--tor' "
2518
raise SqlmapConnectionException(errMsg)
2519
2520
# SOCKS5 to prevent DNS leaks (http://en.wikipedia.org/wiki/Tor_%28anonymity_network%29)
2521
socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5 if conf.torType == PROXY_TYPE.SOCKS5 else socks.PROXY_TYPE_SOCKS4, LOCALHOST, port)
2522
socks.wrapmodule(_http_client)
2523
2524
def _setHttpOptions():
2525
if conf.chunked and conf.data:
2526
if hasattr(_http_client.HTTPConnection, "_set_content_length"):
2527
_http_client.HTTPConnection._set_content_length = lambda self, *args, **kwargs: None
2528
else:
2529
def putheader(self, header, *values):
2530
if header != HTTP_HEADER.CONTENT_LENGTH:
2531
self._putheader(header, *values)
2532
2533
if not hasattr(_http_client.HTTPConnection, "_putheader"):
2534
_http_client.HTTPConnection._putheader = _http_client.HTTPConnection.putheader
2535
2536
_http_client.HTTPConnection.putheader = putheader
2537
2538
if conf.http10:
2539
_http_client.HTTPConnection._http_vsn = 10
2540
_http_client.HTTPConnection._http_vsn_str = 'HTTP/1.0'
2541
2542
if conf.url and (conf.url.startswith("ws:/") or conf.url.startswith("wss:/")):
2543
try:
2544
from websocket import ABNF
2545
except ImportError:
2546
errMsg = "sqlmap requires third-party module 'websocket-client' "
2547
errMsg += "in order to use WebSocket functionality"
2548
raise SqlmapMissingDependence(errMsg)
2549
2550
def _checkTor():
2551
if not conf.checkTor:
2552
return
2553
2554
infoMsg = "checking Tor connection"
2555
logger.info(infoMsg)
2556
2557
try:
2558
page, _, _ = Request.getPage(url="https://check.torproject.org/api/ip", raise404=False)
2559
tor_status = json.loads(page)
2560
except (SqlmapConnectionException, TypeError, ValueError):
2561
tor_status = None
2562
2563
if not tor_status or not tor_status.get("IsTor"):
2564
errMsg = "it appears that Tor is not properly set. Please try using options '--tor-type' and/or '--tor-port'"
2565
raise SqlmapConnectionException(errMsg)
2566
else:
2567
infoMsg = "Tor is properly being used"
2568
logger.info(infoMsg)
2569
2570
def _basicOptionValidation():
2571
if conf.limitStart is not None and not (isinstance(conf.limitStart, int) and conf.limitStart > 0):
2572
errMsg = "value for option '--start' (limitStart) must be an integer value greater than zero (>0)"
2573
raise SqlmapSyntaxException(errMsg)
2574
2575
if conf.limitStop is not None and not (isinstance(conf.limitStop, int) and conf.limitStop > 0):
2576
errMsg = "value for option '--stop' (limitStop) must be an integer value greater than zero (>0)"
2577
raise SqlmapSyntaxException(errMsg)
2578
2579
if conf.level is not None and not (isinstance(conf.level, int) and conf.level >= 1 and conf.level <= 5):
2580
errMsg = "value for option '--level' must be an integer value from range [1, 5]"
2581
raise SqlmapSyntaxException(errMsg)
2582
2583
if conf.risk is not None and not (isinstance(conf.risk, int) and conf.risk >= 1 and conf.risk <= 3):
2584
errMsg = "value for option '--risk' must be an integer value from range [1, 3]"
2585
raise SqlmapSyntaxException(errMsg)
2586
2587
if isinstance(conf.limitStart, int) and conf.limitStart > 0 and \
2588
isinstance(conf.limitStop, int) and conf.limitStop < conf.limitStart:
2589
warnMsg = "usage of option '--start' (limitStart) which is bigger than value for --stop (limitStop) option is considered unstable"
2590
logger.warning(warnMsg)
2591
2592
if isinstance(conf.firstChar, int) and conf.firstChar > 0 and \
2593
isinstance(conf.lastChar, int) and conf.lastChar < conf.firstChar:
2594
errMsg = "value for option '--first' (firstChar) must be smaller than or equal to value for --last (lastChar) option"
2595
raise SqlmapSyntaxException(errMsg)
2596
2597
if conf.proxyFile and not any((conf.randomAgent, conf.mobile, conf.agent, conf.requestFile)):
2598
warnMsg = "usage of switch '--random-agent' is strongly recommended when "
2599
warnMsg += "using option '--proxy-file'"
2600
logger.warning(warnMsg)
2601
2602
if conf.textOnly and conf.nullConnection:
2603
errMsg = "switch '--text-only' is incompatible with switch '--null-connection'"
2604
raise SqlmapSyntaxException(errMsg)
2605
2606
if conf.uValues and conf.uChar:
2607
errMsg = "option '--union-values' is incompatible with option '--union-char'"
2608
raise SqlmapSyntaxException(errMsg)
2609
2610
if conf.base64Parameter and conf.tamper:
2611
errMsg = "option '--base64' is incompatible with option '--tamper'"
2612
raise SqlmapSyntaxException(errMsg)
2613
2614
if conf.eta and conf.verbose > defaults.verbose:
2615
errMsg = "switch '--eta' is incompatible with option '-v'"
2616
raise SqlmapSyntaxException(errMsg)
2617
2618
if conf.secondUrl and conf.secondReq:
2619
errMsg = "option '--second-url' is incompatible with option '--second-req')"
2620
raise SqlmapSyntaxException(errMsg)
2621
2622
if conf.direct and conf.url:
2623
errMsg = "option '-d' is incompatible with option '-u' ('--url')"
2624
raise SqlmapSyntaxException(errMsg)
2625
2626
if conf.direct and conf.dbms:
2627
errMsg = "option '-d' is incompatible with option '--dbms'"
2628
raise SqlmapSyntaxException(errMsg)
2629
2630
if conf.titles and conf.nullConnection:
2631
errMsg = "switch '--titles' is incompatible with switch '--null-connection'"
2632
raise SqlmapSyntaxException(errMsg)
2633
2634
if conf.dumpTable and conf.search:
2635
errMsg = "switch '--dump' is incompatible with switch '--search'"
2636
raise SqlmapSyntaxException(errMsg)
2637
2638
if conf.chunked and not any((conf.data, conf.requestFile, conf.forms)):
2639
errMsg = "switch '--chunked' requires usage of (POST) options/switches '--data', '-r' or '--forms'"
2640
raise SqlmapSyntaxException(errMsg)
2641
2642
if conf.api and not conf.configFile:
2643
errMsg = "switch '--api' requires usage of option '-c'"
2644
raise SqlmapSyntaxException(errMsg)
2645
2646
if conf.data and conf.nullConnection:
2647
errMsg = "option '--data' is incompatible with switch '--null-connection'"
2648
raise SqlmapSyntaxException(errMsg)
2649
2650
if conf.string and conf.nullConnection:
2651
errMsg = "option '--string' is incompatible with switch '--null-connection'"
2652
raise SqlmapSyntaxException(errMsg)
2653
2654
if conf.notString and conf.nullConnection:
2655
errMsg = "option '--not-string' is incompatible with switch '--null-connection'"
2656
raise SqlmapSyntaxException(errMsg)
2657
2658
if conf.tor and conf.osPwn:
2659
errMsg = "option '--tor' is incompatible with switch '--os-pwn'"
2660
raise SqlmapSyntaxException(errMsg)
2661
2662
if conf.noCast and conf.hexConvert:
2663
errMsg = "switch '--no-cast' is incompatible with switch '--hex'"
2664
raise SqlmapSyntaxException(errMsg)
2665
2666
if conf.crawlDepth:
2667
try:
2668
xrange(conf.crawlDepth)
2669
except OverflowError as ex:
2670
errMsg = "invalid value used for option '--crawl' ('%s')" % getSafeExString(ex)
2671
raise SqlmapSyntaxException(errMsg)
2672
2673
if conf.dumpAll and conf.search:
2674
errMsg = "switch '--dump-all' is incompatible with switch '--search'"
2675
raise SqlmapSyntaxException(errMsg)
2676
2677
if conf.string and conf.notString:
2678
errMsg = "option '--string' is incompatible with switch '--not-string'"
2679
raise SqlmapSyntaxException(errMsg)
2680
2681
if conf.regexp and conf.nullConnection:
2682
errMsg = "option '--regexp' is incompatible with switch '--null-connection'"
2683
raise SqlmapSyntaxException(errMsg)
2684
2685
if conf.regexp:
2686
try:
2687
re.compile(conf.regexp)
2688
except Exception as ex:
2689
errMsg = "invalid regular expression '%s' ('%s')" % (conf.regexp, getSafeExString(ex))
2690
raise SqlmapSyntaxException(errMsg)
2691
2692
if conf.paramExclude:
2693
if re.search(r"\A\w+,", conf.paramExclude):
2694
conf.paramExclude = r"\A(%s)\Z" % ('|'.join(re.escape(_).strip() for _ in conf.paramExclude.split(',')))
2695
2696
try:
2697
re.compile(conf.paramExclude)
2698
except Exception as ex:
2699
errMsg = "invalid regular expression '%s' ('%s')" % (conf.paramExclude, getSafeExString(ex))
2700
raise SqlmapSyntaxException(errMsg)
2701
2702
if conf.retryOn:
2703
try:
2704
re.compile(conf.retryOn)
2705
except Exception as ex:
2706
errMsg = "invalid regular expression '%s' ('%s')" % (conf.retryOn, getSafeExString(ex))
2707
raise SqlmapSyntaxException(errMsg)
2708
2709
if conf.retries == defaults.retries:
2710
conf.retries = 5 * conf.retries
2711
2712
warnMsg = "increasing default value for "
2713
warnMsg += "option '--retries' to %d because " % conf.retries
2714
warnMsg += "option '--retry-on' was provided"
2715
logger.warning(warnMsg)
2716
2717
if conf.cookieDel and len(conf.cookieDel) != 1:
2718
errMsg = "option '--cookie-del' should contain a single character (e.g. ';')"
2719
raise SqlmapSyntaxException(errMsg)
2720
2721
if conf.crawlExclude:
2722
try:
2723
re.compile(conf.crawlExclude)
2724
except Exception as ex:
2725
errMsg = "invalid regular expression '%s' ('%s')" % (conf.crawlExclude, getSafeExString(ex))
2726
raise SqlmapSyntaxException(errMsg)
2727
2728
if conf.scope:
2729
try:
2730
re.compile(conf.scope)
2731
except Exception as ex:
2732
errMsg = "invalid regular expression '%s' ('%s')" % (conf.scope, getSafeExString(ex))
2733
raise SqlmapSyntaxException(errMsg)
2734
2735
if conf.dumpTable and conf.dumpAll:
2736
errMsg = "switch '--dump' is incompatible with switch '--dump-all'"
2737
raise SqlmapSyntaxException(errMsg)
2738
2739
if conf.predictOutput and (conf.threads > 1 or conf.optimize):
2740
errMsg = "switch '--predict-output' is incompatible with option '--threads' and switch '-o'"
2741
raise SqlmapSyntaxException(errMsg)
2742
2743
if conf.threads > MAX_NUMBER_OF_THREADS and not conf.get("skipThreadCheck"):
2744
errMsg = "maximum number of used threads is %d avoiding potential connection issues" % MAX_NUMBER_OF_THREADS
2745
raise SqlmapSyntaxException(errMsg)
2746
2747
if conf.forms and not any((conf.url, conf.googleDork, conf.bulkFile)):
2748
errMsg = "switch '--forms' requires usage of option '-u' ('--url'), '-g' or '-m'"
2749
raise SqlmapSyntaxException(errMsg)
2750
2751
if conf.crawlExclude and not conf.crawlDepth:
2752
errMsg = "option '--crawl-exclude' requires usage of switch '--crawl'"
2753
raise SqlmapSyntaxException(errMsg)
2754
2755
if conf.safePost and not conf.safeUrl:
2756
errMsg = "option '--safe-post' requires usage of option '--safe-url'"
2757
raise SqlmapSyntaxException(errMsg)
2758
2759
if conf.safeFreq and not any((conf.safeUrl, conf.safeReqFile)):
2760
errMsg = "option '--safe-freq' requires usage of option '--safe-url' or '--safe-req'"
2761
raise SqlmapSyntaxException(errMsg)
2762
2763
if conf.safeReqFile and any((conf.safeUrl, conf.safePost)):
2764
errMsg = "option '--safe-req' is incompatible with option '--safe-url' and option '--safe-post'"
2765
raise SqlmapSyntaxException(errMsg)
2766
2767
if conf.csrfUrl and not conf.csrfToken:
2768
errMsg = "option '--csrf-url' requires usage of option '--csrf-token'"
2769
raise SqlmapSyntaxException(errMsg)
2770
2771
if conf.csrfMethod and not conf.csrfToken:
2772
errMsg = "option '--csrf-method' requires usage of option '--csrf-token'"
2773
raise SqlmapSyntaxException(errMsg)
2774
2775
if conf.csrfData and not conf.csrfToken:
2776
errMsg = "option '--csrf-data' requires usage of option '--csrf-token'"
2777
raise SqlmapSyntaxException(errMsg)
2778
2779
if conf.csrfToken and conf.threads > 1:
2780
errMsg = "option '--csrf-url' is incompatible with option '--threads'"
2781
raise SqlmapSyntaxException(errMsg)
2782
2783
if conf.requestFile and conf.url and conf.url != DUMMY_URL:
2784
errMsg = "option '-r' is incompatible with option '-u' ('--url')"
2785
raise SqlmapSyntaxException(errMsg)
2786
2787
if conf.direct and conf.proxy:
2788
errMsg = "option '-d' is incompatible with option '--proxy'"
2789
raise SqlmapSyntaxException(errMsg)
2790
2791
if conf.direct and conf.tor:
2792
errMsg = "option '-d' is incompatible with switch '--tor'"
2793
raise SqlmapSyntaxException(errMsg)
2794
2795
if not conf.technique:
2796
errMsg = "option '--technique' can't be empty"
2797
raise SqlmapSyntaxException(errMsg)
2798
2799
if conf.tor and conf.ignoreProxy:
2800
errMsg = "switch '--tor' is incompatible with switch '--ignore-proxy'"
2801
raise SqlmapSyntaxException(errMsg)
2802
2803
if conf.tor and conf.proxy:
2804
errMsg = "switch '--tor' is incompatible with option '--proxy'"
2805
raise SqlmapSyntaxException(errMsg)
2806
2807
if conf.proxy and conf.proxyFile:
2808
errMsg = "switch '--proxy' is incompatible with option '--proxy-file'"
2809
raise SqlmapSyntaxException(errMsg)
2810
2811
if conf.proxyFreq and not conf.proxyFile:
2812
errMsg = "option '--proxy-freq' requires usage of option '--proxy-file'"
2813
raise SqlmapSyntaxException(errMsg)
2814
2815
if conf.checkTor and not any((conf.tor, conf.proxy)):
2816
errMsg = "switch '--check-tor' requires usage of switch '--tor' (or option '--proxy' with HTTP proxy address of Tor service)"
2817
raise SqlmapSyntaxException(errMsg)
2818
2819
if conf.torPort is not None and not (isinstance(conf.torPort, int) and conf.torPort >= 0 and conf.torPort <= 65535):
2820
errMsg = "value for option '--tor-port' must be in range [0, 65535]"
2821
raise SqlmapSyntaxException(errMsg)
2822
2823
if conf.torType not in getPublicTypeMembers(PROXY_TYPE, True):
2824
errMsg = "option '--tor-type' accepts one of following values: %s" % ", ".join(getPublicTypeMembers(PROXY_TYPE, True))
2825
raise SqlmapSyntaxException(errMsg)
2826
2827
if conf.dumpFormat not in getPublicTypeMembers(DUMP_FORMAT, True):
2828
errMsg = "option '--dump-format' accepts one of following values: %s" % ", ".join(getPublicTypeMembers(DUMP_FORMAT, True))
2829
raise SqlmapSyntaxException(errMsg)
2830
2831
if conf.uValues and (not re.search(r"\A['\w\s.,()%s-]+\Z" % CUSTOM_INJECTION_MARK_CHAR, conf.uValues) or conf.uValues.count(CUSTOM_INJECTION_MARK_CHAR) != 1):
2832
errMsg = "option '--union-values' must contain valid UNION column values, along with the injection position "
2833
errMsg += "(e.g. 'NULL,1,%s,NULL')" % CUSTOM_INJECTION_MARK_CHAR
2834
raise SqlmapSyntaxException(errMsg)
2835
2836
if conf.skip and conf.testParameter:
2837
if intersect(conf.skip, conf.testParameter):
2838
errMsg = "option '--skip' is incompatible with option '-p'"
2839
raise SqlmapSyntaxException(errMsg)
2840
2841
if conf.rParam and conf.testParameter:
2842
if intersect(conf.rParam, conf.testParameter):
2843
errMsg = "option '--randomize' is incompatible with option '-p'"
2844
raise SqlmapSyntaxException(errMsg)
2845
2846
if conf.mobile and conf.agent:
2847
errMsg = "switch '--mobile' is incompatible with option '--user-agent'"
2848
raise SqlmapSyntaxException(errMsg)
2849
2850
if conf.proxy and conf.ignoreProxy:
2851
errMsg = "option '--proxy' is incompatible with switch '--ignore-proxy'"
2852
raise SqlmapSyntaxException(errMsg)
2853
2854
if conf.alert and conf.alert.startswith('-'):
2855
errMsg = "value for option '--alert' must be valid operating system command(s)"
2856
raise SqlmapSyntaxException(errMsg)
2857
2858
if conf.timeSec < 1:
2859
errMsg = "value for option '--time-sec' must be a positive integer"
2860
raise SqlmapSyntaxException(errMsg)
2861
2862
if conf.hashFile and any((conf.direct, conf.url, conf.logFile, conf.bulkFile, conf.googleDork, conf.configFile, conf.requestFile, conf.updateAll, conf.smokeTest, conf.wizard, conf.dependencies, conf.purge, conf.listTampers)):
2863
errMsg = "option '--crack' should be used as a standalone"
2864
raise SqlmapSyntaxException(errMsg)
2865
2866
if isinstance(conf.uCols, six.string_types):
2867
if not conf.uCols.isdigit() and ("-" not in conf.uCols or len(conf.uCols.split("-")) != 2):
2868
errMsg = "value for option '--union-cols' must be a range with hyphon "
2869
errMsg += "(e.g. 1-10) or integer value (e.g. 5)"
2870
raise SqlmapSyntaxException(errMsg)
2871
2872
if conf.dbmsCred and ':' not in conf.dbmsCred:
2873
errMsg = "value for option '--dbms-cred' must be in "
2874
errMsg += "format <username>:<password> (e.g. \"root:pass\")"
2875
raise SqlmapSyntaxException(errMsg)
2876
2877
if conf.encoding:
2878
_ = checkCharEncoding(conf.encoding, False)
2879
if _ is None:
2880
errMsg = "unknown encoding '%s'. Please visit " % conf.encoding
2881
errMsg += "'%s' to get the full list of " % CODECS_LIST_PAGE
2882
errMsg += "supported encodings"
2883
raise SqlmapSyntaxException(errMsg)
2884
else:
2885
conf.encoding = _
2886
2887
if conf.fileWrite and not os.path.isfile(conf.fileWrite):
2888
errMsg = "file '%s' does not exist" % os.path.abspath(conf.fileWrite)
2889
raise SqlmapFilePathException(errMsg)
2890
2891
if conf.loadCookies and not os.path.exists(conf.loadCookies):
2892
errMsg = "cookies file '%s' does not exist" % os.path.abspath(conf.loadCookies)
2893
raise SqlmapFilePathException(errMsg)
2894
2895
def initOptions(inputOptions=AttribDict(), overrideOptions=False):
2896
_setConfAttributes()
2897
_setKnowledgeBaseAttributes()
2898
_mergeOptions(inputOptions, overrideOptions)
2899
2900
def init():
2901
"""
2902
Set attributes into both configuration and knowledge base singletons
2903
based upon command line and configuration file options.
2904
"""
2905
2906
_useWizardInterface()
2907
setVerbosity()
2908
_saveConfig()
2909
_setRequestFromFile()
2910
_cleanupOptions()
2911
_cleanupEnvironment()
2912
_purge()
2913
_checkDependencies()
2914
_createHomeDirectories()
2915
_createTemporaryDirectory()
2916
_basicOptionValidation()
2917
_setProxyList()
2918
_setTorProxySettings()
2919
_setDNSServer()
2920
_adjustLoggingFormatter()
2921
_setMultipleTargets()
2922
_listTamperingFunctions()
2923
_setTamperingFunctions()
2924
_setPreprocessFunctions()
2925
_setPostprocessFunctions()
2926
_setTrafficOutputFP()
2927
_setupHTTPCollector()
2928
_setHttpOptions()
2929
2930
parseTargetDirect()
2931
2932
if any((conf.url, conf.logFile, conf.bulkFile, conf.requestFile, conf.googleDork, conf.stdinPipe)):
2933
_setHostname()
2934
_setHTTPTimeout()
2935
_setHTTPExtraHeaders()
2936
_setHTTPCookies()
2937
_setHTTPReferer()
2938
_setHTTPHost()
2939
_setHTTPUserAgent()
2940
_setHTTPAuthentication()
2941
_setHTTPHandlers()
2942
_setDNSCache()
2943
_setSocketPreConnect()
2944
_setSafeVisit()
2945
_doSearch()
2946
_setStdinPipeTargets()
2947
_setBulkMultipleTargets()
2948
_checkTor()
2949
_setCrawler()
2950
_findPageForms()
2951
_setDBMS()
2952
_setTechnique()
2953
2954
_setThreads()
2955
_setOS()
2956
_setWriteFile()
2957
_setMetasploit()
2958
_setDBMSAuthentication()
2959
loadBoundaries()
2960
loadPayloads()
2961
_setPrefixSuffix()
2962
update()
2963
_loadQueries()
2964
2965