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