2019-05-08 13:47:52 +03:00
|
|
|
#!/usr/bin/env python
|
2012-07-20 22:17:35 +04:00
|
|
|
|
|
|
|
"""
|
2020-12-31 13:46:27 +03:00
|
|
|
Copyright (c) 2006-2021 sqlmap developers (http://sqlmap.org/)
|
2017-10-11 15:50:46 +03:00
|
|
|
See the file 'LICENSE' for copying permission
|
2012-07-20 22:17:35 +04:00
|
|
|
"""
|
|
|
|
|
2019-01-22 03:28:24 +03:00
|
|
|
from __future__ import print_function
|
|
|
|
|
2012-07-20 22:17:35 +04:00
|
|
|
import re
|
2014-11-11 13:53:51 +03:00
|
|
|
import sys
|
2012-07-20 22:17:35 +04:00
|
|
|
|
|
|
|
from lib.core.common import Backend
|
|
|
|
from lib.core.common import dataToStdout
|
|
|
|
from lib.core.common import getSQLSnippet
|
2013-02-13 12:57:16 +04:00
|
|
|
from lib.core.common import isStackingAvailable
|
2019-05-06 01:54:21 +03:00
|
|
|
from lib.core.convert import getUnicode
|
2012-07-20 22:17:35 +04:00
|
|
|
from lib.core.data import conf
|
|
|
|
from lib.core.data import logger
|
2012-08-21 13:19:15 +04:00
|
|
|
from lib.core.dicts import SQL_STATEMENTS
|
2014-09-16 11:07:31 +04:00
|
|
|
from lib.core.enums import AUTOCOMPLETE_TYPE
|
2020-05-13 15:18:19 +03:00
|
|
|
from lib.core.enums import DBMS
|
2015-11-23 11:20:35 +03:00
|
|
|
from lib.core.exception import SqlmapNoneDataException
|
2021-03-28 22:41:45 +03:00
|
|
|
from lib.core.settings import METADB_SUFFIX
|
2013-09-02 13:32:32 +04:00
|
|
|
from lib.core.settings import NULL
|
2012-07-20 22:17:35 +04:00
|
|
|
from lib.core.settings import PARAMETER_SPLITTING_REGEX
|
|
|
|
from lib.core.shell import autoCompletion
|
|
|
|
from lib.request import inject
|
2019-05-02 01:45:44 +03:00
|
|
|
from thirdparty.six.moves import input as _input
|
2012-07-20 22:17:35 +04:00
|
|
|
|
2019-05-29 17:42:04 +03:00
|
|
|
class Custom(object):
|
2012-07-20 22:17:35 +04:00
|
|
|
"""
|
|
|
|
This class defines custom enumeration functionalities for plugins.
|
|
|
|
"""
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def sqlQuery(self, query):
|
|
|
|
output = None
|
|
|
|
sqlType = None
|
|
|
|
query = query.rstrip(';')
|
|
|
|
|
2015-11-23 11:20:35 +03:00
|
|
|
try:
|
|
|
|
for sqlTitle, sqlStatements in SQL_STATEMENTS.items():
|
|
|
|
for sqlStatement in sqlStatements:
|
|
|
|
if query.lower().startswith(sqlStatement):
|
|
|
|
sqlType = sqlTitle
|
|
|
|
break
|
2012-07-20 22:17:35 +04:00
|
|
|
|
2020-05-06 01:36:18 +03:00
|
|
|
if not re.search(r"\b(OPENROWSET|INTO)\b", query, re.I) and (not sqlType or "SELECT" in sqlType):
|
2015-11-23 11:20:35 +03:00
|
|
|
infoMsg = "fetching %s query output: '%s'" % (sqlType if sqlType is not None else "SQL", query)
|
|
|
|
logger.info(infoMsg)
|
2012-07-20 22:17:35 +04:00
|
|
|
|
2020-05-13 15:18:19 +03:00
|
|
|
if Backend.isDbms(DBMS.MSSQL):
|
|
|
|
match = re.search(r"(\bFROM\s+)([^\s]+)", query, re.I)
|
|
|
|
if match and match.group(2).count('.') == 1:
|
|
|
|
query = query.replace(match.group(0), "%s%s" % (match.group(1), match.group(2).replace('.', ".dbo.")))
|
|
|
|
|
2021-03-28 22:41:45 +03:00
|
|
|
query = re.sub(r"(?i)\w+%s\.?" % METADB_SUFFIX, "", query)
|
|
|
|
|
2015-11-23 11:20:35 +03:00
|
|
|
output = inject.getValue(query, fromUser=True)
|
2012-07-20 22:17:35 +04:00
|
|
|
|
2015-11-23 11:20:35 +03:00
|
|
|
return output
|
|
|
|
elif not isStackingAvailable() and not conf.direct:
|
2019-05-30 23:55:54 +03:00
|
|
|
warnMsg = "execution of non-query SQL statements is only "
|
|
|
|
warnMsg += "available when stacked queries are supported"
|
|
|
|
logger.warn(warnMsg)
|
2012-07-20 22:17:35 +04:00
|
|
|
|
2019-05-30 23:55:54 +03:00
|
|
|
return None
|
2012-07-20 22:17:35 +04:00
|
|
|
else:
|
2015-11-23 11:20:35 +03:00
|
|
|
if sqlType:
|
2019-11-26 15:36:06 +03:00
|
|
|
infoMsg = "executing %s statement: '%s'" % (sqlType if sqlType is not None else "SQL", query)
|
2015-11-23 11:20:35 +03:00
|
|
|
else:
|
2019-11-26 15:36:06 +03:00
|
|
|
infoMsg = "executing unknown SQL command: '%s'" % query
|
|
|
|
logger.info(infoMsg)
|
2012-07-20 22:17:35 +04:00
|
|
|
|
2015-11-23 11:20:35 +03:00
|
|
|
inject.goStacked(query)
|
2012-07-20 22:17:35 +04:00
|
|
|
|
2015-11-23 11:20:35 +03:00
|
|
|
output = NULL
|
|
|
|
|
2019-01-22 02:40:48 +03:00
|
|
|
except SqlmapNoneDataException as ex:
|
2015-11-23 11:20:35 +03:00
|
|
|
logger.warn(ex)
|
2012-07-20 22:17:35 +04:00
|
|
|
|
|
|
|
return output
|
|
|
|
|
|
|
|
def sqlShell(self):
|
|
|
|
infoMsg = "calling %s shell. To quit type " % Backend.getIdentifiedDbms()
|
|
|
|
infoMsg += "'x' or 'q' and press ENTER"
|
|
|
|
logger.info(infoMsg)
|
|
|
|
|
2014-09-16 11:07:31 +04:00
|
|
|
autoCompletion(AUTOCOMPLETE_TYPE.SQL)
|
2012-07-20 22:17:35 +04:00
|
|
|
|
|
|
|
while True:
|
|
|
|
query = None
|
|
|
|
|
|
|
|
try:
|
2019-05-02 01:45:44 +03:00
|
|
|
query = _input("sql-shell> ")
|
2014-11-11 13:53:51 +03:00
|
|
|
query = getUnicode(query, encoding=sys.stdin.encoding)
|
2018-08-17 20:45:34 +03:00
|
|
|
query = query.strip("; ")
|
2012-07-20 22:17:35 +04:00
|
|
|
except KeyboardInterrupt:
|
2019-01-22 03:28:24 +03:00
|
|
|
print()
|
2012-07-20 22:17:35 +04:00
|
|
|
errMsg = "user aborted"
|
|
|
|
logger.error(errMsg)
|
|
|
|
except EOFError:
|
2019-01-22 03:28:24 +03:00
|
|
|
print()
|
2012-07-20 22:17:35 +04:00
|
|
|
errMsg = "exit"
|
|
|
|
logger.error(errMsg)
|
|
|
|
break
|
|
|
|
|
|
|
|
if not query:
|
|
|
|
continue
|
|
|
|
|
|
|
|
if query.lower() in ("x", "q", "exit", "quit"):
|
|
|
|
break
|
|
|
|
|
|
|
|
output = self.sqlQuery(query)
|
|
|
|
|
|
|
|
if output and output != "Quit":
|
2019-04-30 15:04:39 +03:00
|
|
|
conf.dumper.sqlQuery(query, output)
|
2012-07-20 22:17:35 +04:00
|
|
|
|
|
|
|
elif not output:
|
|
|
|
pass
|
|
|
|
|
|
|
|
elif output != "Quit":
|
|
|
|
dataToStdout("No output\n")
|
|
|
|
|
|
|
|
def sqlFile(self):
|
|
|
|
infoMsg = "executing SQL statements from given file(s)"
|
|
|
|
logger.info(infoMsg)
|
|
|
|
|
2016-12-20 01:47:39 +03:00
|
|
|
for filename in re.split(PARAMETER_SPLITTING_REGEX, conf.sqlFile):
|
|
|
|
filename = filename.strip()
|
2012-07-20 22:17:35 +04:00
|
|
|
|
2016-12-20 01:47:39 +03:00
|
|
|
if not filename:
|
2012-07-20 22:17:35 +04:00
|
|
|
continue
|
|
|
|
|
2016-12-20 01:47:39 +03:00
|
|
|
snippet = getSQLSnippet(Backend.getDbms(), filename)
|
2012-07-20 22:17:35 +04:00
|
|
|
|
2019-01-22 05:14:23 +03:00
|
|
|
if snippet and all(query.strip().upper().startswith("SELECT") for query in (_ for _ in snippet.split(';' if ';' in snippet else '\n') if _)):
|
|
|
|
for query in (_ for _ in snippet.split(';' if ';' in snippet else '\n') if _):
|
2015-08-23 23:54:08 +03:00
|
|
|
query = query.strip()
|
|
|
|
if query:
|
2019-04-30 15:04:39 +03:00
|
|
|
conf.dumper.sqlQuery(query, self.sqlQuery(query))
|
2015-08-23 23:54:08 +03:00
|
|
|
else:
|
2019-04-30 15:04:39 +03:00
|
|
|
conf.dumper.sqlQuery(snippet, self.sqlQuery(snippet))
|