2019-05-08 13:47:52 +03:00
|
|
|
#!/usr/bin/env python
|
2008-10-15 19:38:22 +04:00
|
|
|
|
|
|
|
"""
|
2022-01-03 13:30:34 +03:00
|
|
|
Copyright (c) 2006-2022 sqlmap developers (https://sqlmap.org/)
|
2017-10-11 15:50:46 +03:00
|
|
|
See the file 'LICENSE' for copying permission
|
2008-10-15 19:38:22 +04:00
|
|
|
"""
|
|
|
|
|
2019-06-04 13:15:39 +03:00
|
|
|
from __future__ import division
|
|
|
|
|
2011-05-16 02:21:38 +04:00
|
|
|
import os
|
2010-10-15 04:34:16 +04:00
|
|
|
import re
|
2022-11-21 02:37:48 +03:00
|
|
|
import subprocess
|
2017-05-08 00:12:42 +03:00
|
|
|
import time
|
2010-10-15 04:34:16 +04:00
|
|
|
|
2008-10-15 19:38:22 +04:00
|
|
|
from lib.controller.action import action
|
|
|
|
from lib.controller.checks import checkConnection
|
2019-06-04 15:44:06 +03:00
|
|
|
from lib.controller.checks import checkDynParam
|
2017-05-08 00:12:42 +03:00
|
|
|
from lib.controller.checks import checkInternet
|
2010-09-16 12:43:10 +04:00
|
|
|
from lib.controller.checks import checkNullConnection
|
2019-06-04 15:44:06 +03:00
|
|
|
from lib.controller.checks import checkSqlInjection
|
|
|
|
from lib.controller.checks import checkStability
|
2011-07-06 09:44:47 +04:00
|
|
|
from lib.controller.checks import checkWaf
|
2011-01-03 11:32:06 +03:00
|
|
|
from lib.controller.checks import heuristicCheckSqlInjection
|
2010-11-28 21:10:54 +03:00
|
|
|
from lib.core.agent import agent
|
2014-04-07 22:28:17 +04:00
|
|
|
from lib.core.common import dataToStdout
|
2011-03-29 02:48:00 +04:00
|
|
|
from lib.core.common import extractRegexResult
|
2011-01-14 19:12:44 +03:00
|
|
|
from lib.core.common import getFilteredPageContent
|
2011-05-16 02:21:38 +04:00
|
|
|
from lib.core.common import getPublicTypeMembers
|
2015-09-10 16:51:33 +03:00
|
|
|
from lib.core.common import getSafeExString
|
2012-02-24 17:07:20 +04:00
|
|
|
from lib.core.common import hashDBRetrieve
|
|
|
|
from lib.core.common import hashDBWrite
|
2011-02-14 00:58:48 +03:00
|
|
|
from lib.core.common import intersect
|
2019-10-07 15:20:18 +03:00
|
|
|
from lib.core.common import isDigit
|
2015-01-04 00:30:21 +03:00
|
|
|
from lib.core.common import isListLike
|
2010-03-05 18:25:53 +03:00
|
|
|
from lib.core.common import parseTargetUrl
|
2015-03-26 13:40:19 +03:00
|
|
|
from lib.core.common import popValue
|
|
|
|
from lib.core.common import pushValue
|
2019-11-14 16:21:53 +03:00
|
|
|
from lib.core.common import randomInt
|
2011-03-29 02:48:00 +04:00
|
|
|
from lib.core.common import randomStr
|
2008-10-15 19:38:22 +04:00
|
|
|
from lib.core.common import readInput
|
2019-05-14 14:58:42 +03:00
|
|
|
from lib.core.common import removePostHintPrefix
|
2012-12-28 00:15:44 +04:00
|
|
|
from lib.core.common import safeCSValue
|
2011-01-02 10:37:47 +03:00
|
|
|
from lib.core.common import showHttpErrorCodes
|
2012-07-31 13:03:44 +04:00
|
|
|
from lib.core.common import urldecode
|
2019-06-04 15:44:06 +03:00
|
|
|
from lib.core.common import urlencode
|
2019-03-28 18:04:38 +03:00
|
|
|
from lib.core.compat import xrange
|
2008-10-15 19:38:22 +04:00
|
|
|
from lib.core.data import conf
|
|
|
|
from lib.core.data import kb
|
|
|
|
from lib.core.data import logger
|
2018-04-01 13:45:47 +03:00
|
|
|
from lib.core.decorators import stackedmethod
|
2013-01-30 19:30:34 +04:00
|
|
|
from lib.core.enums import CONTENT_TYPE
|
2011-12-28 17:50:03 +04:00
|
|
|
from lib.core.enums import HASHDB_KEYS
|
2012-08-22 13:56:30 +04:00
|
|
|
from lib.core.enums import HEURISTIC_TEST
|
2019-04-09 00:49:55 +03:00
|
|
|
from lib.core.enums import HTTP_HEADER
|
2010-11-08 12:44:32 +03:00
|
|
|
from lib.core.enums import HTTPMETHOD
|
2016-05-06 14:06:59 +03:00
|
|
|
from lib.core.enums import NOTE
|
2010-11-28 21:10:54 +03:00
|
|
|
from lib.core.enums import PAYLOAD
|
2010-11-08 12:44:32 +03:00
|
|
|
from lib.core.enums import PLACE
|
2013-01-14 14:22:38 +04:00
|
|
|
from lib.core.exception import SqlmapBaseException
|
2020-01-09 13:25:09 +03:00
|
|
|
from lib.core.exception import SqlmapConnectionException
|
2012-12-06 17:14:19 +04:00
|
|
|
from lib.core.exception import SqlmapNoneDataException
|
|
|
|
from lib.core.exception import SqlmapNotVulnerableException
|
|
|
|
from lib.core.exception import SqlmapSilentQuitException
|
2017-07-26 00:32:30 +03:00
|
|
|
from lib.core.exception import SqlmapSkipTargetException
|
2018-10-09 00:34:55 +03:00
|
|
|
from lib.core.exception import SqlmapSystemException
|
2012-12-06 17:14:19 +04:00
|
|
|
from lib.core.exception import SqlmapUserQuitException
|
2019-06-04 15:44:06 +03:00
|
|
|
from lib.core.exception import SqlmapValueException
|
2012-10-19 13:02:14 +04:00
|
|
|
from lib.core.settings import ASP_NET_CONTROL_REGEX
|
2018-10-27 00:01:19 +03:00
|
|
|
from lib.core.settings import CSRF_TOKEN_PARAMETER_INFIXES
|
2011-11-22 01:31:08 +04:00
|
|
|
from lib.core.settings import DEFAULT_GET_POST_DELIMITER
|
2011-03-29 02:48:00 +04:00
|
|
|
from lib.core.settings import EMPTY_FORM_FIELDS_REGEX
|
2013-12-04 12:56:37 +04:00
|
|
|
from lib.core.settings import GOOGLE_ANALYTICS_COOKIE_PREFIX
|
2011-12-20 16:52:41 +04:00
|
|
|
from lib.core.settings import HOST_ALIASES
|
2019-06-04 15:44:06 +03:00
|
|
|
from lib.core.settings import IGNORE_PARAMETERS
|
|
|
|
from lib.core.settings import LOW_TEXT_PERCENT
|
2011-02-14 00:58:48 +03:00
|
|
|
from lib.core.settings import REFERER_ALIASES
|
|
|
|
from lib.core.settings import USER_AGENT_ALIASES
|
2010-03-15 14:55:13 +03:00
|
|
|
from lib.core.target import initTargetEnv
|
|
|
|
from lib.core.target import setupTargetEnv
|
2018-12-17 19:38:47 +03:00
|
|
|
from lib.utils.hash import crackHashFile
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2012-12-06 17:14:19 +04:00
|
|
|
def _selectInjection():
|
2008-10-15 19:38:22 +04:00
|
|
|
"""
|
|
|
|
Selection function for injection place, parameters and type.
|
|
|
|
"""
|
|
|
|
|
2011-07-04 23:58:41 +04:00
|
|
|
points = {}
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2011-07-04 23:58:41 +04:00
|
|
|
for injection in kb.injections:
|
|
|
|
place = injection.place
|
|
|
|
parameter = injection.parameter
|
|
|
|
ptype = injection.ptype
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2010-11-28 21:10:54 +03:00
|
|
|
point = (place, parameter, ptype)
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2010-11-28 21:10:54 +03:00
|
|
|
if point not in points:
|
2011-07-04 23:58:41 +04:00
|
|
|
points[point] = injection
|
|
|
|
else:
|
2019-01-22 05:00:44 +03:00
|
|
|
for key in points[point]:
|
2011-07-04 23:58:41 +04:00
|
|
|
if key != 'data':
|
|
|
|
points[point][key] = points[point][key] or injection[key]
|
|
|
|
points[point]['data'].update(injection['data'])
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2010-11-28 21:10:54 +03:00
|
|
|
if len(points) == 1:
|
|
|
|
kb.injection = kb.injections[0]
|
2010-11-30 17:48:13 +03:00
|
|
|
|
2010-11-28 21:10:54 +03:00
|
|
|
elif len(points) > 1:
|
|
|
|
message = "there were multiple injection points, please select "
|
|
|
|
message += "the one to use for following injections:\n"
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2010-11-28 21:10:54 +03:00
|
|
|
points = []
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2010-11-28 21:10:54 +03:00
|
|
|
for i in xrange(0, len(kb.injections)):
|
|
|
|
place = kb.injections[i].place
|
|
|
|
parameter = kb.injections[i].parameter
|
|
|
|
ptype = kb.injections[i].ptype
|
|
|
|
point = (place, parameter, ptype)
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2010-11-28 21:10:54 +03:00
|
|
|
if point not in points:
|
|
|
|
points.append(point)
|
2010-11-29 04:04:42 +03:00
|
|
|
ptype = PAYLOAD.PARAMETER[ptype] if isinstance(ptype, int) else ptype
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2010-11-28 21:10:54 +03:00
|
|
|
message += "[%d] place: %s, parameter: " % (i, place)
|
2010-11-29 04:04:42 +03:00
|
|
|
message += "%s, type: %s" % (parameter, ptype)
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2010-11-28 21:10:54 +03:00
|
|
|
if i == 0:
|
|
|
|
message += " (default)"
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2010-11-28 21:10:54 +03:00
|
|
|
message += "\n"
|
|
|
|
|
|
|
|
message += "[q] Quit"
|
2017-04-19 15:46:27 +03:00
|
|
|
choice = readInput(message, default='0').upper()
|
2010-11-28 21:10:54 +03:00
|
|
|
|
2019-10-07 15:20:18 +03:00
|
|
|
if isDigit(choice) and int(choice) < len(kb.injections) and int(choice) >= 0:
|
2017-04-19 15:46:27 +03:00
|
|
|
index = int(choice)
|
|
|
|
elif choice == 'Q':
|
2012-12-06 17:14:19 +04:00
|
|
|
raise SqlmapUserQuitException
|
2010-11-28 21:10:54 +03:00
|
|
|
else:
|
|
|
|
errMsg = "invalid choice"
|
2013-01-04 02:20:55 +04:00
|
|
|
raise SqlmapValueException(errMsg)
|
2010-11-28 21:10:54 +03:00
|
|
|
|
|
|
|
kb.injection = kb.injections[index]
|
|
|
|
|
2012-12-06 17:14:19 +04:00
|
|
|
def _formatInjection(inj):
|
2014-11-21 13:33:57 +03:00
|
|
|
paramType = conf.method if conf.method not in (None, HTTPMETHOD.GET, HTTPMETHOD.POST) else inj.place
|
|
|
|
data = "Parameter: %s (%s)\n" % (inj.parameter, paramType)
|
2010-11-28 21:10:54 +03:00
|
|
|
|
|
|
|
for stype, sdata in inj.data.items():
|
2011-08-03 14:34:50 +04:00
|
|
|
title = sdata.title
|
2012-02-10 19:34:04 +04:00
|
|
|
vector = sdata.vector
|
2012-09-26 13:27:43 +04:00
|
|
|
comment = sdata.comment
|
2013-01-13 19:22:43 +04:00
|
|
|
payload = agent.adjustLateValues(sdata.payload)
|
|
|
|
if inj.place == PLACE.CUSTOM_HEADER:
|
|
|
|
payload = payload.split(',', 1)[1]
|
2011-08-03 14:34:50 +04:00
|
|
|
if stype == PAYLOAD.TECHNIQUE.UNION:
|
2017-04-14 14:08:51 +03:00
|
|
|
count = re.sub(r"(?i)(\(.+\))|(\blimit[^a-z]+)", "", sdata.payload).count(',') + 1
|
2011-08-03 14:34:50 +04:00
|
|
|
title = re.sub(r"\d+ to \d+", str(count), title)
|
2012-10-28 02:36:09 +04:00
|
|
|
vector = agent.forgeUnionQuery("[QUERY]", vector[0], vector[1], vector[2], None, None, vector[5], vector[6])
|
2011-08-03 14:34:50 +04:00
|
|
|
if count == 1:
|
|
|
|
title = title.replace("columns", "column")
|
2012-09-26 13:27:43 +04:00
|
|
|
elif comment:
|
|
|
|
vector = "%s%s" % (vector, comment)
|
2012-12-05 13:45:17 +04:00
|
|
|
data += " Type: %s\n" % PAYLOAD.SQLINJECTION[stype]
|
2011-08-03 14:34:50 +04:00
|
|
|
data += " Title: %s\n" % title
|
2018-03-14 03:02:26 +03:00
|
|
|
data += " Payload: %s\n" % urldecode(payload, unsafe="&", spaceplus=(inj.place != PLACE.GET and kb.postSpaceToPlus))
|
2012-02-10 19:34:04 +04:00
|
|
|
data += " Vector: %s\n\n" % vector if conf.verbose > 1 else "\n"
|
2010-11-28 21:10:54 +03:00
|
|
|
|
2010-11-29 00:27:47 +03:00
|
|
|
return data
|
2010-11-28 21:10:54 +03:00
|
|
|
|
2012-12-06 17:14:19 +04:00
|
|
|
def _showInjections():
|
2018-02-27 14:37:45 +03:00
|
|
|
if conf.wizard and kb.wizardMode:
|
|
|
|
kb.wizardMode = False
|
|
|
|
|
2015-07-10 12:33:12 +03:00
|
|
|
if kb.testQueryCount > 0:
|
|
|
|
header = "sqlmap identified the following injection point(s) with "
|
|
|
|
header += "a total of %d HTTP(s) requests" % kb.testQueryCount
|
|
|
|
else:
|
|
|
|
header = "sqlmap resumed the following injection point(s) from stored session"
|
2010-11-29 00:27:47 +03:00
|
|
|
|
2017-04-10 20:21:22 +03:00
|
|
|
if conf.api:
|
2017-02-06 13:14:45 +03:00
|
|
|
conf.dumper.string("", {"url": conf.url, "query": conf.parameters.get(PLACE.GET), "data": conf.parameters.get(PLACE.POST)}, content_type=CONTENT_TYPE.TARGET)
|
2013-01-30 19:30:34 +04:00
|
|
|
conf.dumper.string("", kb.injections, content_type=CONTENT_TYPE.TECHNIQUES)
|
2013-01-29 19:34:53 +04:00
|
|
|
else:
|
2016-12-20 01:47:39 +03:00
|
|
|
data = "".join(set(_formatInjection(_) for _ in kb.injections)).rstrip("\n")
|
2013-01-29 19:34:53 +04:00
|
|
|
conf.dumper.string(header, data)
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2011-06-09 13:58:42 +04:00
|
|
|
if conf.tamper:
|
2012-12-10 15:40:28 +04:00
|
|
|
warnMsg = "changes made by tampering scripts are not "
|
|
|
|
warnMsg += "included in shown payload content(s)"
|
2022-06-22 13:04:34 +03:00
|
|
|
logger.warning(warnMsg)
|
2012-12-10 15:40:28 +04:00
|
|
|
|
|
|
|
if conf.hpp:
|
|
|
|
warnMsg = "changes made by HTTP parameter pollution are not "
|
|
|
|
warnMsg += "included in shown payload content(s)"
|
2022-06-22 13:04:34 +03:00
|
|
|
logger.warning(warnMsg)
|
2011-06-09 13:58:42 +04:00
|
|
|
|
2012-12-06 17:14:19 +04:00
|
|
|
def _randomFillBlankFields(value):
|
2011-04-11 15:38:41 +04:00
|
|
|
retVal = value
|
|
|
|
|
|
|
|
if extractRegexResult(EMPTY_FORM_FIELDS_REGEX, value):
|
|
|
|
message = "do you want to fill blank fields with random values? [Y/n] "
|
2017-04-18 16:48:05 +03:00
|
|
|
|
2017-04-19 15:46:27 +03:00
|
|
|
if readInput(message, default='Y', boolean=True):
|
2012-09-06 16:13:54 +04:00
|
|
|
for match in re.finditer(EMPTY_FORM_FIELDS_REGEX, retVal):
|
|
|
|
item = match.group("result")
|
2012-10-19 13:02:14 +04:00
|
|
|
if not any(_ in item for _ in IGNORE_PARAMETERS) and not re.search(ASP_NET_CONTROL_REGEX, item):
|
2019-11-14 16:21:53 +03:00
|
|
|
newValue = randomStr() if not re.search(r"^id|id$", item, re.I) else randomInt()
|
2012-09-06 16:13:54 +04:00
|
|
|
if item[-1] == DEFAULT_GET_POST_DELIMITER:
|
2019-11-14 16:21:53 +03:00
|
|
|
retVal = retVal.replace(item, "%s%s%s" % (item[:-1], newValue, DEFAULT_GET_POST_DELIMITER))
|
2012-09-06 16:13:54 +04:00
|
|
|
else:
|
2019-11-14 16:21:53 +03:00
|
|
|
retVal = retVal.replace(item, "%s%s" % (item, newValue))
|
2011-04-11 15:38:41 +04:00
|
|
|
|
|
|
|
return retVal
|
|
|
|
|
2012-12-06 17:14:19 +04:00
|
|
|
def _saveToHashDB():
|
2015-01-04 00:30:21 +03:00
|
|
|
injections = hashDBRetrieve(HASHDB_KEYS.KB_INJECTIONS, True)
|
|
|
|
if not isListLike(injections):
|
|
|
|
injections = []
|
2012-02-27 19:28:36 +04:00
|
|
|
injections.extend(_ for _ in kb.injections if _ and _.place is not None and _.parameter is not None)
|
|
|
|
|
|
|
|
_ = dict()
|
|
|
|
for injection in injections:
|
|
|
|
key = (injection.place, injection.parameter, injection.ptype)
|
|
|
|
if key not in _:
|
|
|
|
_[key] = injection
|
|
|
|
else:
|
|
|
|
_[key].data.update(injection.data)
|
2019-05-02 12:26:31 +03:00
|
|
|
hashDBWrite(HASHDB_KEYS.KB_INJECTIONS, list(_.values()), True)
|
2012-02-27 17:44:07 +04:00
|
|
|
|
2016-03-28 20:55:33 +03:00
|
|
|
_ = hashDBRetrieve(HASHDB_KEYS.KB_ABS_FILE_PATHS, True)
|
|
|
|
hashDBWrite(HASHDB_KEYS.KB_ABS_FILE_PATHS, kb.absFilePaths | (_ if isinstance(_, set) else set()), True)
|
2011-12-28 17:50:03 +04:00
|
|
|
|
2012-02-24 17:07:20 +04:00
|
|
|
if not hashDBRetrieve(HASHDB_KEYS.KB_CHARS):
|
|
|
|
hashDBWrite(HASHDB_KEYS.KB_CHARS, kb.chars, True)
|
2011-12-22 16:20:21 +04:00
|
|
|
|
2012-02-28 18:04:13 +04:00
|
|
|
if not hashDBRetrieve(HASHDB_KEYS.KB_DYNAMIC_MARKINGS):
|
|
|
|
hashDBWrite(HASHDB_KEYS.KB_DYNAMIC_MARKINGS, kb.dynamicMarkings, True)
|
|
|
|
|
2012-12-06 17:14:19 +04:00
|
|
|
def _saveToResultsFile():
|
2011-05-16 02:21:38 +04:00
|
|
|
if not conf.resultsFP:
|
|
|
|
return
|
|
|
|
|
|
|
|
results = {}
|
2016-12-20 01:47:39 +03:00
|
|
|
techniques = dict((_[1], _[0]) for _ in getPublicTypeMembers(PAYLOAD.TECHNIQUE))
|
2011-06-08 19:31:27 +04:00
|
|
|
|
2016-05-24 18:58:35 +03:00
|
|
|
for injection in kb.injections + kb.falsePositives:
|
2016-05-24 15:50:56 +03:00
|
|
|
if injection.place is None or injection.parameter is None:
|
2011-05-16 02:21:38 +04:00
|
|
|
continue
|
|
|
|
|
2016-05-24 15:50:56 +03:00
|
|
|
key = (injection.place, injection.parameter, ';'.join(injection.notes))
|
2011-05-16 02:21:38 +04:00
|
|
|
if key not in results:
|
|
|
|
results[key] = []
|
|
|
|
|
2019-01-22 05:00:44 +03:00
|
|
|
results[key].extend(list(injection.data.keys()))
|
2011-05-16 02:21:38 +04:00
|
|
|
|
2018-10-09 00:34:55 +03:00
|
|
|
try:
|
|
|
|
for key, value in results.items():
|
|
|
|
place, parameter, notes = key
|
|
|
|
line = "%s,%s,%s,%s,%s%s" % (safeCSValue(kb.originalUrls.get(conf.url) or conf.url), place, parameter, "".join(techniques[_][0].upper() for _ in sorted(value)), notes, os.linesep)
|
|
|
|
conf.resultsFP.write(line)
|
2011-05-16 02:21:38 +04:00
|
|
|
|
2018-10-09 00:34:55 +03:00
|
|
|
conf.resultsFP.flush()
|
2019-01-22 02:40:48 +03:00
|
|
|
except IOError as ex:
|
2019-11-01 19:27:30 +03:00
|
|
|
errMsg = "unable to write to the results file '%s' ('%s'). " % (conf.resultsFile, getSafeExString(ex))
|
2018-10-09 00:34:55 +03:00
|
|
|
raise SqlmapSystemException(errMsg)
|
2011-06-08 18:15:34 +04:00
|
|
|
|
2018-04-01 13:45:47 +03:00
|
|
|
@stackedmethod
|
2008-10-15 19:38:22 +04:00
|
|
|
def start():
|
|
|
|
"""
|
|
|
|
This function calls a function that performs checks on both URL
|
|
|
|
stability and all GET, POST, Cookie and User-Agent parameters to
|
|
|
|
check if they are dynamic and SQL injection affected
|
|
|
|
"""
|
|
|
|
|
2018-12-17 19:38:47 +03:00
|
|
|
if conf.hashFile:
|
|
|
|
crackHashFile(conf.hashFile)
|
|
|
|
|
2010-03-27 02:23:25 +03:00
|
|
|
if conf.direct:
|
|
|
|
initTargetEnv()
|
|
|
|
setupTargetEnv()
|
|
|
|
action()
|
2010-09-26 18:56:55 +04:00
|
|
|
return True
|
2010-03-27 02:23:25 +03:00
|
|
|
|
2012-08-22 18:50:01 +04:00
|
|
|
if conf.url and not any((conf.forms, conf.crawlDepth)):
|
2014-10-22 15:49:29 +04:00
|
|
|
kb.targets.add((conf.url, conf.method, conf.data, conf.cookie, None))
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2012-10-30 21:38:10 +04:00
|
|
|
if conf.configFile and not kb.targets:
|
2011-04-30 17:20:05 +04:00
|
|
|
errMsg = "you did not edit the configuration file properly, set "
|
2013-04-09 13:48:42 +04:00
|
|
|
errMsg += "the target URL, list of targets or google dork"
|
2008-10-15 19:38:22 +04:00
|
|
|
logger.error(errMsg)
|
2010-09-26 18:56:55 +04:00
|
|
|
return False
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2020-10-14 12:34:52 +03:00
|
|
|
if kb.targets and isListLike(kb.targets) and len(kb.targets) > 1:
|
2019-11-07 02:03:06 +03:00
|
|
|
infoMsg = "found a total of %d targets" % len(kb.targets)
|
2008-11-28 01:33:33 +03:00
|
|
|
logger.info(infoMsg)
|
|
|
|
|
2021-08-26 19:08:48 +03:00
|
|
|
targetCount = 0
|
2014-10-22 15:49:29 +04:00
|
|
|
initialHeaders = list(conf.httpHeaders)
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2014-10-22 15:49:29 +04:00
|
|
|
for targetUrl, targetMethod, targetData, targetCookie, targetHeaders in kb.targets:
|
2021-08-26 19:08:48 +03:00
|
|
|
targetCount += 1
|
|
|
|
|
2010-03-16 15:14:02 +03:00
|
|
|
try:
|
2017-05-08 00:12:42 +03:00
|
|
|
if conf.checkInternet:
|
2018-03-16 16:28:37 +03:00
|
|
|
infoMsg = "checking for Internet connection"
|
2017-05-08 00:12:42 +03:00
|
|
|
logger.info(infoMsg)
|
|
|
|
|
|
|
|
if not checkInternet():
|
|
|
|
warnMsg = "[%s] [WARNING] no connection detected" % time.strftime("%X")
|
|
|
|
dataToStdout(warnMsg)
|
|
|
|
|
2020-01-09 13:25:09 +03:00
|
|
|
valid = False
|
|
|
|
for _ in xrange(conf.retries):
|
|
|
|
if checkInternet():
|
|
|
|
valid = True
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
dataToStdout('.')
|
|
|
|
time.sleep(5)
|
|
|
|
|
|
|
|
if not valid:
|
|
|
|
errMsg = "please check your Internet connection and rerun"
|
|
|
|
raise SqlmapConnectionException(errMsg)
|
|
|
|
else:
|
|
|
|
dataToStdout("\n")
|
2017-05-08 00:12:42 +03:00
|
|
|
|
2011-04-30 17:20:05 +04:00
|
|
|
conf.url = targetUrl
|
2019-11-13 13:07:46 +03:00
|
|
|
conf.method = targetMethod.upper().strip() if targetMethod else targetMethod
|
2011-04-30 17:20:05 +04:00
|
|
|
conf.data = targetData
|
2010-03-16 15:14:02 +03:00
|
|
|
conf.cookie = targetCookie
|
2014-10-22 15:49:29 +04:00
|
|
|
conf.httpHeaders = list(initialHeaders)
|
|
|
|
conf.httpHeaders.extend(targetHeaders or [])
|
2019-04-09 00:49:55 +03:00
|
|
|
|
|
|
|
if conf.randomAgent or conf.mobile:
|
|
|
|
for header, value in initialHeaders:
|
|
|
|
if header.upper() == HTTP_HEADER.USER_AGENT.upper():
|
|
|
|
conf.httpHeaders.append((header, value))
|
|
|
|
break
|
|
|
|
|
2020-06-25 14:02:56 +03:00
|
|
|
if conf.data:
|
|
|
|
# Note: explicitly URL encode __ ASP(.NET) parameters (e.g. to avoid problems with Base64 encoded '+' character) - standard procedure in web browsers
|
|
|
|
conf.data = re.sub(r"\b(__\w+)=([^&]+)", lambda match: "%s=%s" % (match.group(1), urlencode(match.group(2), safe='%')), conf.data)
|
2020-06-25 13:55:10 +03:00
|
|
|
|
2018-11-29 02:09:05 +03:00
|
|
|
conf.httpHeaders = [conf.httpHeaders[i] for i in xrange(len(conf.httpHeaders)) if conf.httpHeaders[i][0].upper() not in (__[0].upper() for __ in conf.httpHeaders[i + 1:])]
|
2010-10-15 13:54:29 +04:00
|
|
|
|
2010-10-15 04:34:16 +04:00
|
|
|
initTargetEnv()
|
|
|
|
parseTargetUrl()
|
2010-10-15 13:54:29 +04:00
|
|
|
|
2010-10-15 04:34:16 +04:00
|
|
|
testSqlInj = False
|
2011-04-22 01:15:23 +04:00
|
|
|
|
2019-04-19 12:24:34 +03:00
|
|
|
if PLACE.GET in conf.parameters and not any((conf.data, conf.testParameter)):
|
2014-04-06 19:24:27 +04:00
|
|
|
for parameter in re.findall(r"([^=]+)=([^%s]+%s?|\Z)" % (re.escape(conf.paramDel or "") or DEFAULT_GET_POST_DELIMITER, re.escape(conf.paramDel or "") or DEFAULT_GET_POST_DELIMITER), conf.parameters[PLACE.GET]):
|
2011-04-11 15:38:41 +04:00
|
|
|
paramKey = (conf.hostname, conf.path, PLACE.GET, parameter[0])
|
2011-04-22 01:15:23 +04:00
|
|
|
|
2010-10-15 04:34:16 +04:00
|
|
|
if paramKey not in kb.testedParams:
|
|
|
|
testSqlInj = True
|
|
|
|
break
|
2010-10-15 13:54:29 +04:00
|
|
|
else:
|
|
|
|
paramKey = (conf.hostname, conf.path, None, None)
|
|
|
|
if paramKey not in kb.testedParams:
|
|
|
|
testSqlInj = True
|
|
|
|
|
2013-08-13 20:55:23 +04:00
|
|
|
if testSqlInj and conf.hostname in kb.vulnHosts:
|
|
|
|
if kb.skipVulnHost is None:
|
2013-08-13 20:58:24 +04:00
|
|
|
message = "SQL injection vulnerability has already been detected "
|
2013-08-13 20:55:23 +04:00
|
|
|
message += "against '%s'. Do you want to skip " % conf.hostname
|
|
|
|
message += "further tests involving it? [Y/n]"
|
2017-04-18 16:48:05 +03:00
|
|
|
|
2017-04-19 15:46:27 +03:00
|
|
|
kb.skipVulnHost = readInput(message, default='Y', boolean=True)
|
2017-04-18 16:48:05 +03:00
|
|
|
|
2013-08-13 20:55:23 +04:00
|
|
|
testSqlInj = not kb.skipVulnHost
|
2011-01-07 18:41:09 +03:00
|
|
|
|
2010-10-15 04:34:16 +04:00
|
|
|
if not testSqlInj:
|
|
|
|
infoMsg = "skipping '%s'" % targetUrl
|
|
|
|
logger.info(infoMsg)
|
|
|
|
continue
|
2010-03-16 15:14:02 +03:00
|
|
|
|
|
|
|
if conf.multipleTargets:
|
2015-10-28 16:03:21 +03:00
|
|
|
if conf.forms and conf.method:
|
2021-08-31 14:04:45 +03:00
|
|
|
message = "[%d/%s] Form:\n%s %s" % (targetCount, len(kb.targets) if isListLike(kb.targets) else '?', conf.method, targetUrl)
|
2010-11-15 14:50:33 +03:00
|
|
|
else:
|
2021-08-31 14:04:45 +03:00
|
|
|
message = "[%d/%s] URL:\n%s %s" % (targetCount, len(kb.targets) if isListLike(kb.targets) else '?', HTTPMETHOD.GET, targetUrl)
|
2008-11-28 01:33:33 +03:00
|
|
|
|
2010-03-16 15:14:02 +03:00
|
|
|
if conf.cookie:
|
|
|
|
message += "\nCookie: %s" % conf.cookie
|
2008-11-28 01:33:33 +03:00
|
|
|
|
2012-11-13 13:21:11 +04:00
|
|
|
if conf.data is not None:
|
2020-07-16 15:30:50 +03:00
|
|
|
message += "\n%s data: %s" % ((conf.method if conf.method != HTTPMETHOD.GET else None) or HTTPMETHOD.POST, urlencode(conf.data or "") if re.search(r"\A\s*[<{]", conf.data or "") is None else conf.data)
|
2010-11-15 14:34:57 +03:00
|
|
|
|
2015-10-28 16:03:21 +03:00
|
|
|
if conf.forms and conf.method:
|
2010-11-15 14:34:57 +03:00
|
|
|
if conf.method == HTTPMETHOD.GET and targetUrl.find("?") == -1:
|
|
|
|
continue
|
|
|
|
|
|
|
|
message += "\ndo you want to test this form? [Y/n/q] "
|
2017-04-19 15:46:27 +03:00
|
|
|
choice = readInput(message, default='Y').upper()
|
2010-11-15 14:34:57 +03:00
|
|
|
|
2017-04-19 15:19:39 +03:00
|
|
|
if choice == 'N':
|
|
|
|
continue
|
|
|
|
elif choice == 'Q':
|
|
|
|
break
|
|
|
|
else:
|
2014-11-21 13:20:54 +03:00
|
|
|
if conf.method != HTTPMETHOD.GET:
|
2019-10-03 16:09:59 +03:00
|
|
|
message = "Edit %s data [default: %s]%s: " % (conf.method, urlencode(conf.data or "") if re.search(r"\A\s*[<{]", conf.data or "None") is None else conf.data, " (Warning: blank fields detected)" if conf.data and extractRegexResult(EMPTY_FORM_FIELDS_REGEX, conf.data) else "")
|
2011-03-29 02:48:00 +04:00
|
|
|
conf.data = readInput(message, default=conf.data)
|
2012-12-06 17:14:19 +04:00
|
|
|
conf.data = _randomFillBlankFields(conf.data)
|
2011-11-22 01:31:08 +04:00
|
|
|
conf.data = urldecode(conf.data) if conf.data and urlencode(DEFAULT_GET_POST_DELIMITER, None) not in conf.data else conf.data
|
2010-11-15 14:34:57 +03:00
|
|
|
|
2014-11-21 13:20:54 +03:00
|
|
|
else:
|
2018-02-07 18:05:41 +03:00
|
|
|
if '?' in targetUrl:
|
|
|
|
firstPart, secondPart = targetUrl.split('?', 1)
|
2010-11-15 14:34:57 +03:00
|
|
|
message = "Edit GET data [default: %s]: " % secondPart
|
|
|
|
test = readInput(message, default=secondPart)
|
2012-12-06 17:14:19 +04:00
|
|
|
test = _randomFillBlankFields(test)
|
2010-11-15 14:34:57 +03:00
|
|
|
conf.url = "%s?%s" % (firstPart, test)
|
|
|
|
|
2011-04-11 15:38:41 +04:00
|
|
|
parseTargetUrl()
|
|
|
|
|
2010-12-20 13:48:53 +03:00
|
|
|
else:
|
2020-03-05 00:43:50 +03:00
|
|
|
if not conf.scope:
|
|
|
|
message += "\ndo you want to test this URL? [Y/n/q]"
|
|
|
|
choice = readInput(message, default='Y').upper()
|
|
|
|
|
|
|
|
if choice == 'N':
|
|
|
|
dataToStdout(os.linesep)
|
|
|
|
continue
|
|
|
|
elif choice == 'Q':
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
pass
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2013-04-09 13:48:42 +04:00
|
|
|
infoMsg = "testing URL '%s'" % targetUrl
|
2011-04-30 19:29:59 +04:00
|
|
|
logger.info(infoMsg)
|
2010-03-16 18:21:42 +03:00
|
|
|
|
2010-03-16 15:14:02 +03:00
|
|
|
setupTargetEnv()
|
|
|
|
|
2021-12-02 19:01:02 +03:00
|
|
|
if not checkConnection(suppressOutput=conf.forms):
|
2008-10-15 19:38:22 +04:00
|
|
|
continue
|
|
|
|
|
2019-08-22 12:41:06 +03:00
|
|
|
if conf.rParam and kb.originalPage:
|
|
|
|
kb.randomPool = dict([_ for _ in kb.randomPool.items() if isinstance(_[1], list)])
|
|
|
|
|
|
|
|
for match in re.finditer(r"(?si)<select[^>]+\bname\s*=\s*[\"']([^\"']+)(.+?)</select>", kb.originalPage):
|
|
|
|
name, _ = match.groups()
|
|
|
|
options = tuple(re.findall(r"<option[^>]+\bvalue\s*=\s*[\"']([^\"']+)", _))
|
|
|
|
if options:
|
|
|
|
kb.randomPool[name] = options
|
|
|
|
|
2015-01-06 16:01:47 +03:00
|
|
|
checkWaf()
|
2011-07-06 09:44:47 +04:00
|
|
|
|
2010-10-17 01:52:16 +04:00
|
|
|
if conf.nullConnection:
|
2010-09-16 14:01:33 +04:00
|
|
|
checkNullConnection()
|
2010-09-16 12:43:10 +04:00
|
|
|
|
2018-03-13 15:45:42 +03:00
|
|
|
if (len(kb.injections) == 0 or (len(kb.injections) == 1 and kb.injections[0].place is None)) and (kb.injection.place is None or kb.injection.parameter is None):
|
2019-06-07 01:21:43 +03:00
|
|
|
if not any((conf.string, conf.notString, conf.regexp)) and PAYLOAD.TECHNIQUE.BOOLEAN in conf.technique:
|
2010-03-16 15:14:02 +03:00
|
|
|
# NOTE: this is not needed anymore, leaving only to display
|
|
|
|
# a warning message to the user in case the page is not stable
|
|
|
|
checkStability()
|
2009-04-22 15:48:07 +04:00
|
|
|
|
2013-01-04 02:57:07 +04:00
|
|
|
# Do a little prioritization reorder of a testable parameter list
|
2019-01-22 05:00:44 +03:00
|
|
|
parameters = list(conf.parameters.keys())
|
2010-11-08 15:36:48 +03:00
|
|
|
|
2013-01-06 00:16:47 +04:00
|
|
|
# Order of testing list (first to last)
|
2013-01-13 19:22:43 +04:00
|
|
|
orderList = (PLACE.CUSTOM_POST, PLACE.CUSTOM_HEADER, PLACE.URI, PLACE.POST, PLACE.GET)
|
2011-03-28 20:14:08 +04:00
|
|
|
|
2013-01-06 00:16:47 +04:00
|
|
|
for place in orderList[::-1]:
|
2010-11-08 02:37:15 +03:00
|
|
|
if place in parameters:
|
|
|
|
parameters.remove(place)
|
|
|
|
parameters.insert(0, place)
|
|
|
|
|
2010-12-01 01:40:25 +03:00
|
|
|
proceed = True
|
2010-11-08 02:37:15 +03:00
|
|
|
for place in parameters:
|
2011-02-14 00:08:42 +03:00
|
|
|
# Test User-Agent and Referer headers only if
|
|
|
|
# --level >= 3
|
2019-12-06 17:15:39 +03:00
|
|
|
skip = (place == PLACE.USER_AGENT and (kb.testOnlyCustom or conf.level < 3))
|
|
|
|
skip |= (place == PLACE.REFERER and (kb.testOnlyCustom or conf.level < 3))
|
2011-03-29 10:38:19 +04:00
|
|
|
|
2019-05-17 12:10:34 +03:00
|
|
|
# --param-filter
|
|
|
|
skip |= (len(conf.paramFilter) > 0 and place.upper() not in conf.paramFilter)
|
|
|
|
|
2011-12-20 16:52:41 +04:00
|
|
|
# Test Host header only if
|
|
|
|
# --level >= 5
|
2019-12-06 17:15:39 +03:00
|
|
|
skip |= (place == PLACE.HOST and (kb.testOnlyCustom or conf.level < 5))
|
2011-12-20 16:52:41 +04:00
|
|
|
|
2011-02-14 00:08:42 +03:00
|
|
|
# Test Cookie header only if --level >= 2
|
2019-12-06 17:15:39 +03:00
|
|
|
skip |= (place == PLACE.COOKIE and (kb.testOnlyCustom or conf.level < 2))
|
2010-11-29 19:33:20 +03:00
|
|
|
|
2012-07-26 14:26:57 +04:00
|
|
|
skip |= (place == PLACE.USER_AGENT and intersect(USER_AGENT_ALIASES, conf.skip, True) not in ([], None))
|
2011-08-29 17:47:32 +04:00
|
|
|
skip |= (place == PLACE.REFERER and intersect(REFERER_ALIASES, conf.skip, True) not in ([], None))
|
2012-02-12 23:22:33 +04:00
|
|
|
skip |= (place == PLACE.COOKIE and intersect(PLACE.COOKIE, conf.skip, True) not in ([], None))
|
2015-10-06 15:17:35 +03:00
|
|
|
skip |= (place == PLACE.HOST and intersect(PLACE.HOST, conf.skip, True) not in ([], None))
|
2011-08-29 17:47:32 +04:00
|
|
|
|
2012-07-26 14:26:57 +04:00
|
|
|
skip &= not (place == PLACE.USER_AGENT and intersect(USER_AGENT_ALIASES, conf.testParameter, True))
|
2011-08-29 17:47:32 +04:00
|
|
|
skip &= not (place == PLACE.REFERER and intersect(REFERER_ALIASES, conf.testParameter, True))
|
2011-12-20 16:52:41 +04:00
|
|
|
skip &= not (place == PLACE.HOST and intersect(HOST_ALIASES, conf.testParameter, True))
|
2013-05-12 18:24:13 +04:00
|
|
|
skip &= not (place == PLACE.COOKIE and intersect((PLACE.COOKIE,), conf.testParameter, True))
|
2011-02-14 00:58:48 +03:00
|
|
|
|
2011-03-29 10:38:19 +04:00
|
|
|
if skip:
|
2010-11-29 19:33:20 +03:00
|
|
|
continue
|
|
|
|
|
2022-03-21 16:33:48 +03:00
|
|
|
if place not in conf.paramDict or place not in conf.parameters:
|
2010-03-16 15:14:02 +03:00
|
|
|
continue
|
2009-04-22 15:48:07 +04:00
|
|
|
|
2010-03-16 15:14:02 +03:00
|
|
|
paramDict = conf.paramDict[place]
|
2011-04-22 01:53:35 +04:00
|
|
|
|
2014-11-21 13:20:54 +03:00
|
|
|
paramType = conf.method if conf.method not in (None, HTTPMETHOD.GET, HTTPMETHOD.POST) else place
|
|
|
|
|
2010-03-16 15:14:02 +03:00
|
|
|
for parameter, value in paramDict.items():
|
2010-12-31 18:00:19 +03:00
|
|
|
if not proceed:
|
|
|
|
break
|
|
|
|
|
2011-05-24 21:15:25 +04:00
|
|
|
kb.vainRun = False
|
|
|
|
testSqlInj = True
|
2011-06-08 19:31:27 +04:00
|
|
|
paramKey = (conf.hostname, conf.path, place, parameter)
|
2011-05-24 21:15:25 +04:00
|
|
|
|
2010-07-30 00:01:04 +04:00
|
|
|
if paramKey in kb.testedParams:
|
|
|
|
testSqlInj = False
|
2010-10-15 04:34:16 +04:00
|
|
|
|
2019-05-21 13:07:19 +03:00
|
|
|
infoMsg = "skipping previously processed %sparameter '%s'" % ("%s " % paramType if paramType != parameter else "", parameter)
|
2010-10-15 04:34:16 +04:00
|
|
|
logger.info(infoMsg)
|
|
|
|
|
2019-05-14 14:58:42 +03:00
|
|
|
elif any(_ in conf.testParameter for _ in (parameter, removePostHintPrefix(parameter))):
|
2011-08-29 17:29:42 +04:00
|
|
|
pass
|
|
|
|
|
2019-02-05 15:42:44 +03:00
|
|
|
elif parameter in conf.rParam:
|
2011-08-29 16:50:52 +04:00
|
|
|
testSqlInj = False
|
|
|
|
|
2019-05-21 13:07:19 +03:00
|
|
|
infoMsg = "skipping randomizing %sparameter '%s'" % ("%s " % paramType if paramType != parameter else "", parameter)
|
2011-08-29 16:50:52 +04:00
|
|
|
logger.info(infoMsg)
|
|
|
|
|
2016-05-02 12:10:12 +03:00
|
|
|
elif parameter in conf.skip or kb.postHint and parameter.split(' ')[-1] in conf.skip:
|
2011-08-29 17:29:42 +04:00
|
|
|
testSqlInj = False
|
|
|
|
|
2019-05-21 13:07:19 +03:00
|
|
|
infoMsg = "skipping %sparameter '%s'" % ("%s " % paramType if paramType != parameter else "", parameter)
|
2011-08-29 17:29:42 +04:00
|
|
|
logger.info(infoMsg)
|
2011-06-16 18:11:30 +04:00
|
|
|
|
2016-12-28 14:25:05 +03:00
|
|
|
elif conf.paramExclude and (re.search(conf.paramExclude, parameter, re.I) or kb.postHint and re.search(conf.paramExclude, parameter.split(' ')[-1], re.I)):
|
2016-12-26 01:16:44 +03:00
|
|
|
testSqlInj = False
|
|
|
|
|
2019-05-21 13:07:19 +03:00
|
|
|
infoMsg = "skipping %sparameter '%s'" % ("%s " % paramType if paramType != parameter else "", parameter)
|
2016-12-26 01:16:44 +03:00
|
|
|
logger.info(infoMsg)
|
|
|
|
|
2018-12-10 17:22:53 +03:00
|
|
|
elif conf.csrfToken and re.search(conf.csrfToken, parameter, re.I):
|
2014-10-23 13:23:53 +04:00
|
|
|
testSqlInj = False
|
|
|
|
|
2014-11-17 13:50:05 +03:00
|
|
|
infoMsg = "skipping anti-CSRF token parameter '%s'" % parameter
|
2014-10-23 13:23:53 +04:00
|
|
|
logger.info(infoMsg)
|
|
|
|
|
2011-08-02 21:35:43 +04:00
|
|
|
# Ignore session-like parameters for --level < 4
|
2018-10-27 00:01:19 +03:00
|
|
|
elif conf.level < 4 and (parameter.upper() in IGNORE_PARAMETERS or any(_ in parameter.lower() for _ in CSRF_TOKEN_PARAMETER_INFIXES) or parameter.upper().startswith(GOOGLE_ANALYTICS_COOKIE_PREFIX)):
|
2011-04-13 23:01:02 +04:00
|
|
|
testSqlInj = False
|
|
|
|
|
2019-05-21 13:07:19 +03:00
|
|
|
infoMsg = "ignoring %sparameter '%s'" % ("%s " % paramType if paramType != parameter else "", parameter)
|
2011-04-13 23:01:02 +04:00
|
|
|
logger.info(infoMsg)
|
|
|
|
|
2019-06-07 01:21:43 +03:00
|
|
|
elif PAYLOAD.TECHNIQUE.BOOLEAN in conf.technique or conf.skipStatic:
|
2013-01-13 19:22:43 +04:00
|
|
|
check = checkDynParam(place, parameter, value)
|
2012-08-20 14:14:01 +04:00
|
|
|
|
2013-01-13 19:22:43 +04:00
|
|
|
if not check:
|
2019-05-21 13:07:19 +03:00
|
|
|
warnMsg = "%sparameter '%s' does not appear to be dynamic" % ("%s " % paramType if paramType != parameter else "", parameter)
|
2022-06-22 13:04:34 +03:00
|
|
|
logger.warning(warnMsg)
|
2010-10-15 04:34:16 +04:00
|
|
|
|
2015-05-18 21:57:15 +03:00
|
|
|
if conf.skipStatic:
|
2019-05-21 13:07:19 +03:00
|
|
|
infoMsg = "skipping static %sparameter '%s'" % ("%s " % paramType if paramType != parameter else "", parameter)
|
2015-05-18 21:57:15 +03:00
|
|
|
logger.info(infoMsg)
|
|
|
|
|
|
|
|
testSqlInj = False
|
2013-01-13 19:22:43 +04:00
|
|
|
else:
|
2019-05-21 13:07:19 +03:00
|
|
|
infoMsg = "%sparameter '%s' appears to be dynamic" % ("%s " % paramType if paramType != parameter else "", parameter)
|
2013-01-13 19:22:43 +04:00
|
|
|
logger.info(infoMsg)
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2010-07-30 00:01:04 +04:00
|
|
|
kb.testedParams.add(paramKey)
|
|
|
|
|
2010-03-16 15:14:02 +03:00
|
|
|
if testSqlInj:
|
2015-07-18 18:01:34 +03:00
|
|
|
try:
|
|
|
|
if place == PLACE.COOKIE:
|
|
|
|
pushValue(kb.mergeCookies)
|
|
|
|
kb.mergeCookies = False
|
2015-03-26 13:40:19 +03:00
|
|
|
|
2015-07-18 18:01:34 +03:00
|
|
|
check = heuristicCheckSqlInjection(place, parameter)
|
2011-04-22 01:53:35 +04:00
|
|
|
|
2015-07-18 18:01:34 +03:00
|
|
|
if check != HEURISTIC_TEST.POSITIVE:
|
|
|
|
if conf.smart or (kb.ignoreCasted and check == HEURISTIC_TEST.CASTED):
|
2019-05-21 13:07:19 +03:00
|
|
|
infoMsg = "skipping %sparameter '%s'" % ("%s " % paramType if paramType != parameter else "", parameter)
|
2015-07-18 18:01:34 +03:00
|
|
|
logger.info(infoMsg)
|
|
|
|
continue
|
2010-10-15 04:34:16 +04:00
|
|
|
|
2019-05-21 13:07:19 +03:00
|
|
|
infoMsg = "testing for SQL injection on %sparameter '%s'" % ("%s " % paramType if paramType != parameter else "", parameter)
|
2015-07-18 18:01:34 +03:00
|
|
|
logger.info(infoMsg)
|
2010-10-15 04:34:16 +04:00
|
|
|
|
2015-07-18 18:01:34 +03:00
|
|
|
injection = checkSqlInjection(place, parameter, value)
|
|
|
|
proceed = not kb.endDetection
|
2016-05-12 17:42:12 +03:00
|
|
|
injectable = False
|
2010-12-22 02:55:55 +03:00
|
|
|
|
2016-04-15 13:04:54 +03:00
|
|
|
if getattr(injection, "place", None) is not None:
|
2016-05-06 14:06:59 +03:00
|
|
|
if NOTE.FALSE_POSITIVE_OR_UNEXPLOITABLE in injection.notes:
|
|
|
|
kb.falsePositives.append(injection)
|
|
|
|
else:
|
2016-05-12 17:42:12 +03:00
|
|
|
injectable = True
|
|
|
|
|
2016-05-06 14:06:59 +03:00
|
|
|
kb.injections.append(injection)
|
2010-12-01 01:40:25 +03:00
|
|
|
|
2022-11-21 02:37:48 +03:00
|
|
|
if not kb.alerted:
|
|
|
|
if conf.alert:
|
|
|
|
infoMsg = "executing alerting shell command(s) ('%s')" % conf.alert
|
|
|
|
logger.info(infoMsg)
|
|
|
|
try:
|
|
|
|
process = subprocess.Popen(conf.alert, shell=True)
|
|
|
|
process.wait()
|
|
|
|
except Exception as ex:
|
|
|
|
errMsg = "error occurred while executing '%s' ('%s')" % (conf.alert, getSafeExString(ex))
|
|
|
|
logger.error(errMsg)
|
|
|
|
|
|
|
|
kb.alerted = True
|
|
|
|
|
2016-05-12 17:42:12 +03:00
|
|
|
# In case when user wants to end detection phase (Ctrl+C)
|
|
|
|
if not proceed:
|
|
|
|
break
|
|
|
|
|
2019-05-21 13:07:19 +03:00
|
|
|
msg = "%sparameter '%s' " % ("%s " % injection.place if injection.place != injection.parameter else "", injection.parameter)
|
2016-05-12 17:42:12 +03:00
|
|
|
msg += "is vulnerable. Do you want to keep testing the others (if any)? [y/N] "
|
2010-12-22 16:15:44 +03:00
|
|
|
|
2017-04-18 16:48:05 +03:00
|
|
|
if not readInput(msg, default='N', boolean=True):
|
2016-05-12 17:42:12 +03:00
|
|
|
proceed = False
|
|
|
|
paramKey = (conf.hostname, conf.path, None, None)
|
|
|
|
kb.testedParams.add(paramKey)
|
2010-12-01 01:40:25 +03:00
|
|
|
|
2016-05-12 17:42:12 +03:00
|
|
|
if not injectable:
|
2019-05-21 13:07:19 +03:00
|
|
|
warnMsg = "%sparameter '%s' does not seem to be injectable" % ("%s " % paramType if paramType != parameter else "", parameter)
|
2022-06-22 13:04:34 +03:00
|
|
|
logger.warning(warnMsg)
|
2008-11-22 04:57:22 +03:00
|
|
|
|
2015-07-18 18:01:34 +03:00
|
|
|
finally:
|
|
|
|
if place == PLACE.COOKIE:
|
|
|
|
kb.mergeCookies = popValue()
|
2015-03-26 13:40:19 +03:00
|
|
|
|
2010-12-01 01:40:25 +03:00
|
|
|
if len(kb.injections) == 0 or (len(kb.injections) == 1 and kb.injections[0].place is None):
|
2011-05-24 21:15:25 +04:00
|
|
|
if kb.vainRun and not conf.multipleTargets:
|
2011-11-15 15:17:39 +04:00
|
|
|
errMsg = "no parameter(s) found for testing in the provided data "
|
2011-05-24 21:15:25 +04:00
|
|
|
errMsg += "(e.g. GET parameter 'id' in 'www.site.com/index.php?id=1')"
|
2019-06-07 01:55:36 +03:00
|
|
|
if kb.originalPage:
|
|
|
|
advice = []
|
|
|
|
if not conf.forms and re.search(r"<form", kb.originalPage) is not None:
|
|
|
|
advice.append("--forms")
|
|
|
|
if not conf.crawlDepth and re.search(r"href=[\"']/?\w", kb.originalPage) is not None:
|
|
|
|
advice.append("--crawl=2")
|
|
|
|
if advice:
|
|
|
|
errMsg += ". You are advised to rerun with '%s'" % ' '.join(advice)
|
2013-01-04 02:20:55 +04:00
|
|
|
raise SqlmapNoneDataException(errMsg)
|
2012-08-20 13:40:49 +04:00
|
|
|
else:
|
2017-11-24 14:20:57 +03:00
|
|
|
errMsg = "all tested parameters do not appear to be injectable."
|
2011-04-06 18:41:44 +04:00
|
|
|
|
2011-04-22 02:04:20 +04:00
|
|
|
if conf.level < 5 or conf.risk < 3:
|
2017-11-24 14:20:57 +03:00
|
|
|
errMsg += " Try to increase values for '--level'/'--risk' options "
|
|
|
|
errMsg += "if you wish to perform more tests."
|
2011-04-22 02:04:20 +04:00
|
|
|
|
2019-06-07 01:21:43 +03:00
|
|
|
if isinstance(conf.technique, list) and len(conf.technique) < 5:
|
2012-02-01 18:49:42 +04:00
|
|
|
errMsg += " Rerun without providing the option '--technique'."
|
2011-01-16 02:11:36 +03:00
|
|
|
|
2011-01-14 19:12:44 +03:00
|
|
|
if not conf.textOnly and kb.originalPage:
|
2011-01-16 21:11:35 +03:00
|
|
|
percent = (100.0 * len(getFilteredPageContent(kb.originalPage)) / len(kb.originalPage))
|
2011-05-27 00:48:18 +04:00
|
|
|
|
2012-08-20 13:28:41 +04:00
|
|
|
if kb.dynamicMarkings:
|
2012-07-23 15:57:38 +04:00
|
|
|
errMsg += " You can give it a go with the switch '--text-only' "
|
|
|
|
errMsg += "if the target page has a low percentage "
|
2011-06-15 21:37:28 +04:00
|
|
|
errMsg += "of textual content (~%.2f%% of " % percent
|
2012-08-20 13:29:23 +04:00
|
|
|
errMsg += "page content is text)."
|
2011-05-27 12:21:02 +04:00
|
|
|
elif percent < LOW_TEXT_PERCENT and not kb.errorIsNone:
|
2012-07-23 15:57:38 +04:00
|
|
|
errMsg += " Please retry with the switch '--text-only' "
|
2011-05-27 00:58:24 +04:00
|
|
|
errMsg += "(along with --technique=BU) as this case "
|
|
|
|
errMsg += "looks like a perfect candidate "
|
2011-05-27 00:48:18 +04:00
|
|
|
errMsg += "(low textual content along with inability "
|
|
|
|
errMsg += "of comparison engine to detect at least "
|
2012-08-20 13:29:23 +04:00
|
|
|
errMsg += "one dynamic parameter)."
|
2011-04-22 01:31:16 +04:00
|
|
|
|
2012-08-22 13:56:30 +04:00
|
|
|
if kb.heuristicTest == HEURISTIC_TEST.POSITIVE:
|
2011-06-15 21:37:28 +04:00
|
|
|
errMsg += " As heuristic test turned out positive you are "
|
2017-11-24 14:20:57 +03:00
|
|
|
errMsg += "strongly advised to continue on with the tests."
|
|
|
|
|
|
|
|
if conf.string:
|
2011-06-15 21:37:28 +04:00
|
|
|
errMsg += " Also, you can try to rerun by providing a "
|
2012-07-23 15:57:38 +04:00
|
|
|
errMsg += "valid value for option '--string' as perhaps the string you "
|
2013-10-15 21:26:24 +04:00
|
|
|
errMsg += "have chosen does not match "
|
2016-05-30 17:46:23 +03:00
|
|
|
errMsg += "exclusively True responses."
|
2011-04-22 01:31:16 +04:00
|
|
|
elif conf.regexp:
|
2011-06-15 21:37:28 +04:00
|
|
|
errMsg += " Also, you can try to rerun by providing a "
|
2012-07-23 15:57:38 +04:00
|
|
|
errMsg += "valid value for option '--regexp' as perhaps the regular "
|
2013-10-15 21:26:24 +04:00
|
|
|
errMsg += "expression that you have chosen "
|
2016-05-30 17:46:23 +03:00
|
|
|
errMsg += "does not match exclusively True responses."
|
2011-01-16 02:11:36 +03:00
|
|
|
|
2014-12-09 11:02:06 +03:00
|
|
|
if not conf.tamper:
|
|
|
|
errMsg += " If you suspect that there is some kind of protection mechanism "
|
2017-11-24 14:20:57 +03:00
|
|
|
errMsg += "involved (e.g. WAF) maybe you could try to use "
|
|
|
|
errMsg += "option '--tamper' (e.g. '--tamper=space2comment')"
|
2014-12-09 11:02:06 +03:00
|
|
|
|
2018-12-18 01:41:04 +03:00
|
|
|
if not conf.randomAgent:
|
|
|
|
errMsg += " and/or switch '--random-agent'"
|
|
|
|
|
2016-05-30 17:46:23 +03:00
|
|
|
raise SqlmapNotVulnerableException(errMsg.rstrip('.'))
|
2010-11-28 21:10:54 +03:00
|
|
|
else:
|
2011-01-12 01:18:47 +03:00
|
|
|
# Flush the flag
|
|
|
|
kb.testMode = False
|
|
|
|
|
2012-12-06 17:14:19 +04:00
|
|
|
_saveToResultsFile()
|
|
|
|
_saveToHashDB()
|
|
|
|
_showInjections()
|
|
|
|
_selectInjection()
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2010-12-01 20:09:52 +03:00
|
|
|
if kb.injection.place is not None and kb.injection.parameter is not None:
|
2012-08-20 13:40:49 +04:00
|
|
|
if conf.multipleTargets:
|
2010-03-16 15:14:02 +03:00
|
|
|
message = "do you want to exploit this SQL injection? [Y/n] "
|
2017-04-18 16:48:05 +03:00
|
|
|
condition = readInput(message, default='Y', boolean=True)
|
2010-03-16 15:14:02 +03:00
|
|
|
else:
|
|
|
|
condition = True
|
|
|
|
|
|
|
|
if condition:
|
|
|
|
action()
|
|
|
|
|
2010-11-05 18:59:25 +03:00
|
|
|
except KeyboardInterrupt:
|
2020-10-14 13:22:56 +03:00
|
|
|
if kb.lastCtrlCTime and (time.time() - kb.lastCtrlCTime < 1):
|
|
|
|
kb.multipleCtrlC = True
|
|
|
|
raise SqlmapUserQuitException("user aborted (Ctrl+C was pressed multiple times)")
|
|
|
|
|
|
|
|
kb.lastCtrlCTime = time.time()
|
|
|
|
|
2010-11-05 19:03:12 +03:00
|
|
|
if conf.multipleTargets:
|
2011-04-08 14:39:07 +04:00
|
|
|
warnMsg = "user aborted in multiple target mode"
|
2022-06-22 13:04:34 +03:00
|
|
|
logger.warning(warnMsg)
|
2010-11-05 18:59:25 +03:00
|
|
|
|
2010-11-07 19:23:03 +03:00
|
|
|
message = "do you want to skip to the next target in list? [Y/n/q]"
|
2017-04-19 15:46:27 +03:00
|
|
|
choice = readInput(message, default='Y').upper()
|
2010-11-05 18:59:25 +03:00
|
|
|
|
2017-04-18 16:48:05 +03:00
|
|
|
if choice == 'N':
|
2010-11-05 19:03:12 +03:00
|
|
|
return False
|
2017-04-18 16:48:05 +03:00
|
|
|
elif choice == 'Q':
|
2012-12-06 17:14:19 +04:00
|
|
|
raise SqlmapUserQuitException
|
2010-11-05 19:03:12 +03:00
|
|
|
else:
|
|
|
|
raise
|
2010-11-05 18:59:25 +03:00
|
|
|
|
2017-07-26 00:32:30 +03:00
|
|
|
except SqlmapSkipTargetException:
|
|
|
|
pass
|
|
|
|
|
2012-12-06 17:14:19 +04:00
|
|
|
except SqlmapUserQuitException:
|
2010-09-30 23:45:23 +04:00
|
|
|
raise
|
|
|
|
|
2012-12-06 17:14:19 +04:00
|
|
|
except SqlmapSilentQuitException:
|
2010-11-10 22:44:51 +03:00
|
|
|
raise
|
|
|
|
|
2019-01-22 02:40:48 +03:00
|
|
|
except SqlmapBaseException as ex:
|
2015-09-10 16:51:33 +03:00
|
|
|
errMsg = getSafeExString(ex)
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2010-03-16 15:14:02 +03:00
|
|
|
if conf.multipleTargets:
|
2016-05-06 14:06:59 +03:00
|
|
|
_saveToResultsFile()
|
|
|
|
|
2021-08-26 19:08:48 +03:00
|
|
|
errMsg += ", skipping to the next target"
|
2016-10-02 12:13:40 +03:00
|
|
|
logger.error(errMsg.lstrip(", "))
|
2010-03-16 15:14:02 +03:00
|
|
|
else:
|
2013-07-27 13:20:43 +04:00
|
|
|
logger.critical(errMsg)
|
2010-09-26 18:56:55 +04:00
|
|
|
return False
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2011-01-02 10:37:47 +03:00
|
|
|
finally:
|
|
|
|
showHttpErrorCodes()
|
|
|
|
|
2012-04-12 13:44:54 +04:00
|
|
|
if kb.maxConnectionsFlag:
|
2013-01-10 16:18:44 +04:00
|
|
|
warnMsg = "it appears that the target "
|
2012-04-12 13:44:54 +04:00
|
|
|
warnMsg += "has a maximum connections "
|
|
|
|
warnMsg += "constraint"
|
2022-06-22 13:04:34 +03:00
|
|
|
logger.warning(warnMsg)
|
2012-04-12 13:44:54 +04:00
|
|
|
|
2011-05-11 00:44:36 +04:00
|
|
|
if kb.dataOutputFlag and not conf.multipleTargets:
|
2012-04-12 13:44:54 +04:00
|
|
|
logger.info("fetched data logged to text files under '%s'" % conf.outputPath)
|
2010-11-03 13:08:27 +03:00
|
|
|
|
2016-05-06 14:06:59 +03:00
|
|
|
if conf.multipleTargets:
|
2019-11-01 19:27:30 +03:00
|
|
|
if conf.resultsFile:
|
2016-05-06 14:06:59 +03:00
|
|
|
infoMsg = "you can find results of scanning in multiple targets "
|
2019-11-01 19:27:30 +03:00
|
|
|
infoMsg += "mode inside the CSV file '%s'" % conf.resultsFile
|
2016-05-06 14:06:59 +03:00
|
|
|
logger.info(infoMsg)
|
2011-05-16 02:21:38 +04:00
|
|
|
|
2010-09-26 18:56:55 +04:00
|
|
|
return True
|