From dc41484b3f2ae89bd892bf4934a838467ab669fb Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 13 Feb 2013 09:57:16 +0100 Subject: [PATCH] Refactoring of funcionality for finding out if stacking is available --- lib/core/common.py | 18 ++++++++++++++++++ lib/takeover/abstraction.py | 9 +++++---- lib/takeover/udf.py | 3 ++- plugins/dbms/mysql/takeover.py | 3 ++- plugins/generic/custom.py | 12 ++---------- plugins/generic/filesystem.py | 9 +++++---- plugins/generic/misc.py | 3 ++- plugins/generic/takeover.py | 19 ++++++++++--------- 8 files changed, 46 insertions(+), 30 deletions(-) diff --git a/lib/core/common.py b/lib/core/common.py index d4289b646..9ccd73636 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -2399,6 +2399,24 @@ def isTechniqueAvailable(technique): else: return getTechniqueData(technique) is not None +def isStackingAvailable(): + """ + Returns True whether techniques using stacking are available + """ + + retVal = False + + if PAYLOAD.TECHNIQUE.STACKED in kb.injection.data: + retVal = True + else: + for technique in getPublicTypeMembers(PAYLOAD.TECHNIQUE, True): + _ = getTechniqueData(technique) + if _ and "stacked" in _["title"].lower(): + retVal = True + break + + return retVal + def isInferenceAvailable(): """ Returns True whether techniques using inference technique are available diff --git a/lib/takeover/abstraction.py b/lib/takeover/abstraction.py index 51fab9854..5d5f3eb6f 100644 --- a/lib/takeover/abstraction.py +++ b/lib/takeover/abstraction.py @@ -9,6 +9,7 @@ from extra.safe2bin.safe2bin import safechardecode from lib.core.common import dataToStdout from lib.core.common import Backend from lib.core.common import getSQLSnippet +from lib.core.common import isStackingAvailable from lib.core.common import isTechniqueAvailable from lib.core.common import readInput from lib.core.data import conf @@ -39,7 +40,7 @@ class Abstraction(Web, UDF, Xp_cmdshell): Xp_cmdshell.__init__(self) def execCmd(self, cmd, silent=False): - if self.webBackdoorUrl and not isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED): + if self.webBackdoorUrl and not isStackingAvailable(): self.webBackdoorRunCmd(cmd) elif Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL): @@ -55,7 +56,7 @@ class Abstraction(Web, UDF, Xp_cmdshell): def evalCmd(self, cmd, first=None, last=None): retVal = None - if self.webBackdoorUrl and not isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED): + if self.webBackdoorUrl and not isStackingAvailable(): retVal = self.webBackdoorRunCmd(cmd) elif Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL): @@ -92,7 +93,7 @@ class Abstraction(Web, UDF, Xp_cmdshell): self.execCmd(cmd) def shell(self): - if self.webBackdoorUrl and not isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED): + if self.webBackdoorUrl and not isStackingAvailable(): infoMsg = "calling OS shell. To quit type " infoMsg += "'x' or 'q' and press ENTER" logger.info(infoMsg) @@ -146,7 +147,7 @@ class Abstraction(Web, UDF, Xp_cmdshell): if not conf.dbmsCred: return - if not conf.direct and not isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED): + if not conf.direct and not isStackingAvailable(): errMsg = "stacked queries is not supported hence sqlmap cannot " errMsg += "execute statements as another user. The execution " errMsg += "will continue and the DBMS credentials provided " diff --git a/lib/takeover/udf.py b/lib/takeover/udf.py index 8375f2a4d..d26066568 100644 --- a/lib/takeover/udf.py +++ b/lib/takeover/udf.py @@ -10,6 +10,7 @@ import os from lib.core.agent import agent from lib.core.common import dataToStdout from lib.core.common import Backend +from lib.core.common import isStackingAvailable from lib.core.common import isTechniqueAvailable from lib.core.common import readInput from lib.core.data import conf @@ -188,7 +189,7 @@ class UDF: logger.error(errMsg) return - if not isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED) and not conf.direct: + if not isStackingAvailable() and not conf.direct: errMsg = "UDF injection feature requires stacked queries SQL injection" logger.error(errMsg) return diff --git a/plugins/dbms/mysql/takeover.py b/plugins/dbms/mysql/takeover.py index 41ebd1135..897cf4206 100644 --- a/plugins/dbms/mysql/takeover.py +++ b/plugins/dbms/mysql/takeover.py @@ -9,6 +9,7 @@ import re from lib.core.agent import agent from lib.core.common import Backend +from lib.core.common import isStackingAvailable from lib.core.common import isTechniqueAvailable from lib.core.common import normalizePath from lib.core.common import ntToPosixSlashes @@ -100,7 +101,7 @@ class Takeover(GenericTakeover): logger.debug("keeping existing UDF '%s' as requested" % udf) def uncPathRequest(self): - if not isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED): + if not isStackingAvailable(): query = agent.prefixQuery("AND LOAD_FILE('%s')" % self.uncPath) query = agent.suffixQuery(query) payload = agent.payload(newValue=query) diff --git a/plugins/generic/custom.py b/plugins/generic/custom.py index d13feb9cc..e940b3ac3 100644 --- a/plugins/generic/custom.py +++ b/plugins/generic/custom.py @@ -12,6 +12,7 @@ from lib.core.common import dataToStdout from lib.core.common import getPublicTypeMembers from lib.core.common import getSQLSnippet from lib.core.common import getTechniqueData +from lib.core.common import isStackingAvailable from lib.core.common import isTechniqueAvailable from lib.core.convert import utf8decode from lib.core.data import conf @@ -41,15 +42,6 @@ class Custom: sqlType = sqlTitle break - stacked = isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED) - - if not stacked: - for technique in getPublicTypeMembers(PAYLOAD.TECHNIQUE, True): - _ = getTechniqueData(technique) - if _ and "stacked" in _["title"].lower(): - stacked = True - break - if "OPENROWSET" not in query.upper() and (not sqlType or "SELECT" in sqlType): infoMsg = "fetching %s query output: '%s'" % (sqlType if sqlType is not None else "SQL", query) logger.info(infoMsg) @@ -57,7 +49,7 @@ class Custom: output = inject.getValue(query, fromUser=True) return output - elif not stacked and not conf.direct: + elif not isStackingAvailable() and not conf.direct: warnMsg = "execution of custom SQL queries is only " warnMsg += "available when stacked queries are supported" logger.warn(warnMsg) diff --git a/plugins/generic/filesystem.py b/plugins/generic/filesystem.py index e9ea439f1..17d9dee8e 100644 --- a/plugins/generic/filesystem.py +++ b/plugins/generic/filesystem.py @@ -14,6 +14,7 @@ from lib.core.common import decloakToTemp from lib.core.common import decodeHexValue from lib.core.common import isNumPosStrValue from lib.core.common import isListLike +from lib.core.common import isStackingAvailable from lib.core.common import isTechniqueAvailable from lib.core.common import readInput from lib.core.data import conf @@ -189,8 +190,8 @@ class Filesystem: fileContent = None kb.fileReadMode = True - if conf.direct or isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED): - if isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED): + if conf.direct or isStackingAvailable(): + if isStackingAvailable(): debugMsg = "going to read the file with stacked query SQL " debugMsg += "injection technique" logger.debug(debugMsg) @@ -260,8 +261,8 @@ class Filesystem: if localFile.endswith('_'): localFile = decloakToTemp(localFile) - if conf.direct or isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED): - if isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED): + if conf.direct or isStackingAvailable(): + if isStackingAvailable(): debugMsg = "going to upload the %s file with " % fileType debugMsg += "stacked query SQL injection technique" logger.debug(debugMsg) diff --git a/plugins/generic/misc.py b/plugins/generic/misc.py index 5fe7fa111..e754a366e 100644 --- a/plugins/generic/misc.py +++ b/plugins/generic/misc.py @@ -10,6 +10,7 @@ import re from lib.core.common import Backend from lib.core.common import hashDBWrite +from lib.core.common import isStackingAvailable from lib.core.common import isTechniqueAvailable from lib.core.common import normalizePath from lib.core.common import ntToPosixSlashes @@ -125,7 +126,7 @@ class Miscellaneous: self.delRemoteFile(self.webStagerFilePath) self.delRemoteFile(self.webBackdoorFilePath) - if not isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED) and not conf.direct: + if not isStackingAvailable() and not conf.direct: return if Backend.isOs(OS.WINDOWS): diff --git a/plugins/generic/takeover.py b/plugins/generic/takeover.py index 412802cc0..2f3b0d21b 100644 --- a/plugins/generic/takeover.py +++ b/plugins/generic/takeover.py @@ -8,6 +8,7 @@ See the file 'doc/COPYING' for copying permission import os from lib.core.common import Backend +from lib.core.common import isStackingAvailable from lib.core.common import isTechniqueAvailable from lib.core.common import readInput from lib.core.common import runningAsAdmin @@ -41,9 +42,9 @@ class Takeover(Abstraction, Metasploit, ICMPsh, Registry, Miscellaneous): Abstraction.__init__(self) def osCmd(self): - if isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED) or conf.direct: + if isStackingAvailable() or conf.direct: web = False - elif not isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED) and Backend.isDbms(DBMS.MYSQL): + elif not isStackingAvailable() and Backend.isDbms(DBMS.MYSQL): infoMsg = "going to use a web backdoor for command execution" logger.info(infoMsg) @@ -63,9 +64,9 @@ class Takeover(Abstraction, Metasploit, ICMPsh, Registry, Miscellaneous): self.cleanup(web=web) def osShell(self): - if isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED) or conf.direct: + if isStackingAvailable() or conf.direct: web = False - elif not isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED) and Backend.isDbms(DBMS.MYSQL): + elif not isStackingAvailable() and Backend.isDbms(DBMS.MYSQL): infoMsg = "going to use a web backdoor for command prompt" logger.info(infoMsg) @@ -153,7 +154,7 @@ class Takeover(Abstraction, Metasploit, ICMPsh, Registry, Miscellaneous): if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL): self.sysUdfs.pop("sys_bineval") - if isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED) or conf.direct: + if isStackingAvailable() or conf.direct: web = False self.getRemoteTempPath() @@ -202,7 +203,7 @@ class Takeover(Abstraction, Metasploit, ICMPsh, Registry, Miscellaneous): self.uploadIcmpshSlave(web=web) self.icmpPwn() - elif not isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED) and Backend.isDbms(DBMS.MYSQL): + elif not isStackingAvailable() and Backend.isDbms(DBMS.MYSQL): web = True infoMsg = "going to use a web backdoor to establish the tunnel" @@ -250,7 +251,7 @@ class Takeover(Abstraction, Metasploit, ICMPsh, Registry, Miscellaneous): errMsg += "relay attack" raise SqlmapUnsupportedDBMSException(errMsg) - if not isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED) and not conf.direct: + if not isStackingAvailable() and not conf.direct: if Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.MSSQL): errMsg = "on this back-end DBMS it is only possible to " errMsg += "perform the SMB relay attack if stacked " @@ -292,7 +293,7 @@ class Takeover(Abstraction, Metasploit, ICMPsh, Registry, Miscellaneous): self.smb() def osBof(self): - if not isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED) and not conf.direct: + if not isStackingAvailable() and not conf.direct: return if not Backend.isDbms(DBMS.MSSQL) or not Backend.isVersionWithin(("2000", "2005")): @@ -328,7 +329,7 @@ class Takeover(Abstraction, Metasploit, ICMPsh, Registry, Miscellaneous): raise SqlmapUndefinedMethod(errMsg) def _regInit(self): - if not isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED) and not conf.direct: + if not isStackingAvailable() and not conf.direct: return self.checkDbmsOs()