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