removed queriesfile.py, implemented XMLObject approach (still shell.py and udf.py TODO)

This commit is contained in:
Miroslav Stampar
2010-10-21 13:13:12 +00:00
parent be443c6947
commit bc79eec702
16 changed files with 169 additions and 401 deletions

View File

@@ -220,8 +220,8 @@ class Agent:
if field.startswith("(CASE"):
nulledCastedField = field
else:
nulledCastedField = queries[kb.dbms].cast % field
nulledCastedField = queries[kb.dbms].isnull % nulledCastedField
nulledCastedField = queries[kb.dbms].cast.query % field
nulledCastedField = queries[kb.dbms].isnull.query % nulledCastedField
return nulledCastedField
@@ -260,7 +260,7 @@ class Agent:
fields = fields.replace(", ", ",")
fieldsSplitted = fields.split(",")
dbmsDelimiter = queries[kb.dbms].delimiter
dbmsDelimiter = queries[kb.dbms].delimiter.query
nulledCastedFields = []
for field in fieldsSplitted:
@@ -516,18 +516,18 @@ class Agent:
"""
limitedQuery = query
limitStr = queries[kb.dbms].limit
limitStr = queries[kb.dbms].limit.query
fromIndex = limitedQuery.index(" FROM ")
untilFrom = limitedQuery[:fromIndex]
fromFrom = limitedQuery[fromIndex+1:]
orderBy = False
if kb.dbms in ( "MySQL", "PostgreSQL", "SQLite" ):
limitStr = queries[kb.dbms].limit % (num, 1)
limitStr = queries[kb.dbms].limit.query % (num, 1)
limitedQuery += " %s" % limitStr
elif kb.dbms == "Firebird":
limitStr = queries[kb.dbms].limit % (num+1, num+1)
limitStr = queries[kb.dbms].limit.query % (num+1, num+1)
limitedQuery += " %s" % limitStr
elif kb.dbms == "Oracle":
@@ -556,7 +556,7 @@ class Agent:
limitedQuery = limitedQuery.replace("DISTINCT %s" % notDistinct, notDistinct)
if limitedQuery.startswith("SELECT TOP ") or limitedQuery.startswith("TOP "):
topNums = re.search(queries[kb.dbms].limitregexp, limitedQuery, re.I)
topNums = re.search(queries[kb.dbms].limitregexp.query, limitedQuery, re.I)
if topNums:
topNums = topNums.groups()
@@ -602,7 +602,7 @@ class Agent:
@rtype: C{str}
"""
return queries[kb.dbms].case % expression
return queries[kb.dbms].case.query % expression
# SQL agent
agent = Agent()

View File

@@ -909,14 +909,14 @@ def getDelayQuery(andCond=False):
banVer = kb.bannerFp["dbmsVersion"]
if (kb.dbms == "MySQL" and banVer >= "5.0.12") or (kb.dbms == "PostgreSQL" and banVer >= "8.2"):
query = queries[kb.dbms].timedelay % conf.timeSec
query = queries[kb.dbms].timedelay.query % conf.timeSec
else:
query = queries[kb.dbms].timedelay2 % conf.timeSec
query = queries[kb.dbms].timedelay.query2 % conf.timeSec
elif kb.dbms == "Firebird":
query = queries[kb.dbms].timedelay
query = queries[kb.dbms].timedelay.query
else:
query = queries[kb.dbms].timedelay % conf.timeSec
query = queries[kb.dbms].timedelay.query % conf.timeSec
if andCond:
if kb.dbms in ( "MySQL", "SQLite" ):
@@ -1078,6 +1078,8 @@ def safeStringFormat(formatStr, params):
if count < len(params):
retVal = retVal[:index] + getUnicode(params[count]) + retVal[index+2:]
else:
import pdb
pdb.set_trace()
raise sqlmapNoneDataException, "wrong number of parameters during string formatting"
count += 1

View File

@@ -37,6 +37,7 @@ from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.data import paths
from lib.core.data import queries
from lib.core.datatype import advancedDict
from lib.core.exception import sqlmapFilePathException
from lib.core.exception import sqlmapGenericException
@@ -55,7 +56,6 @@ from lib.core.settings import SUPPORTED_OS
from lib.core.settings import VERSION_STRING
from lib.core.update import update
from lib.parse.configfile import configFileParser
from lib.parse.queriesfile import queriesParser
from lib.request.proxy import ProxyHTTPSHandler
from lib.request.certhandler import HTTPSCertAuthHandler
from lib.request.redirecthandler import SmartRedirectHandler
@@ -195,6 +195,13 @@ def __feedTargetsDict(reqFile, addedTargetUrls):
kb.targetUrls.add((url, method, data, cookie))
addedTargetUrls.add(url)
def __loadQueries():
"""
Loads queries from 'xml/queries.xml' file.
"""
for node in xmlobject.XMLFile(path=paths.QUERIES_XML, textfilter=sanitizeStr).root.dbms:
queries[node.value] = node
def __setMultipleTargets():
"""
Define a configuration parameter if we are running in multiple target
@@ -1258,4 +1265,4 @@ def init(inputOptions=advancedDict()):
__setMetasploit()
update()
queriesParser()
__loadQueries()

View File

@@ -1,240 +0,0 @@
#!/usr/bin/env python
"""
$Id$
Copyright (c) 2006-2010 sqlmap developers (http://sqlmap.sourceforge.net/)
See the file 'doc/COPYING' for copying permission
"""
from xml.sax.handler import ContentHandler
from lib.core.common import checkFile
from lib.core.common import parseXmlFile
from lib.core.common import sanitizeStr
from lib.core.data import logger
from lib.core.data import queries
from lib.core.data import paths
from lib.core.datatype import advancedDict
class queriesHandler(ContentHandler):
"""
This class defines methods to parse the default DBMS queries
from an XML file
"""
def __init__(self):
self.__dbms = ''
self.__queries = advancedDict()
def startElement(self, name, attrs):
if name == "dbms":
data = sanitizeStr(attrs.get("value"))
self.__dbms = data
elif name == "cast":
data = sanitizeStr(attrs.get("query"))
self.__queries.cast = data
elif name == "length":
data = sanitizeStr(attrs.get("query"))
self.__queries.length = data
elif name == "isnull":
data = sanitizeStr(attrs.get("query"))
self.__queries.isnull = data
elif name == "delimiter":
data = sanitizeStr(attrs.get("query"))
self.__queries.delimiter = data
elif name == "limit":
data = sanitizeStr(attrs.get("query"))
self.__queries.limit = data
elif name == "limitregexp":
data = sanitizeStr(attrs.get("query"))
self.__queries.limitregexp = data
elif name == "limitgroupstart":
data = sanitizeStr(attrs.get("query"))
self.__queries.limitgroupstart = data
elif name == "limitgroupstop":
data = sanitizeStr(attrs.get("query"))
self.__queries.limitgroupstop = data
elif name == "limitstring":
data = sanitizeStr(attrs.get("query"))
self.__queries.limitstring = data
elif name == "order":
data = sanitizeStr(attrs.get("query"))
self.__queries.order = data
elif name == "count":
data = sanitizeStr(attrs.get("query"))
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
data = sanitizeStr(attrs.get("query2"))
self.__queries.timedelay2 = data
elif name == "substring":
data = sanitizeStr(attrs.get("query"))
self.__queries.substring = data
elif name == "case":
data = sanitizeStr(attrs.get("query"))
self.__queries.case = data
elif name == "error":
data = sanitizeStr(attrs.get("query"))
self.__queries.error = data
elif name == "inference":
data = sanitizeStr(attrs.get("query"))
self.__queries.inference = data
elif name == "banner":
data = sanitizeStr(attrs.get("query"))
self.__queries.banner = data
elif name == "current_user":
data = sanitizeStr(attrs.get("query"))
self.__queries.currentUser = data
elif name == "current_db":
data = sanitizeStr(attrs.get("query"))
self.__queries.currentDb = data
elif name == "is_dba":
data = sanitizeStr(attrs.get("query"))
self.__queries.isDba = data
elif name == "check_udf":
data = sanitizeStr(attrs.get("query"))
self.__queries.checkUdf = data
elif name == "inband":
self.__inband = sanitizeStr(attrs.get("query"))
self.__inband2 = sanitizeStr(attrs.get("query2"))
self.__conditionInband = sanitizeStr(attrs.get("condition"))
self.__conditionInband2 = sanitizeStr(attrs.get("condition2"))
elif name == "blind":
self.__blind = sanitizeStr(attrs.get("query"))
self.__blind2 = sanitizeStr(attrs.get("query2"))
self.__count = sanitizeStr(attrs.get("count"))
self.__count2 = sanitizeStr(attrs.get("count2"))
self.__conditionBlind = sanitizeStr(attrs.get("condition"))
self.__conditionBlind2 = sanitizeStr(attrs.get("condition2"))
def endElement(self, name):
if name == "dbms":
queries[self.__dbms] = self.__queries
self.__queries = advancedDict()
elif name == "users":
self.__users = {}
self.__users["inband"] = { "query": self.__inband, "query2": self.__inband2 }
self.__users["blind"] = { "query": self.__blind, "query2": self.__blind2,
"count": self.__count, "count2": self.__count2 }
self.__queries.users = self.__users
elif name == "passwords":
self.__passwords = {}
self.__passwords["inband"] = { "query": self.__inband, "query2": self.__inband2, "condition": self.__conditionInband }
self.__passwords["blind"] = { "query": self.__blind, "query2": self.__blind2,
"count": self.__count, "count2": self.__count2 }
self.__queries.passwords = self.__passwords
elif name == "privileges":
self.__privileges = {}
self.__privileges["inband"] = { "query": self.__inband, "query2": self.__inband2, "condition": self.__conditionInband, "condition2": self.__conditionInband2 }
self.__privileges["blind"] = { "query": self.__blind, "query2": self.__blind2,
"count": self.__count, "count2": self.__count2 }
self.__queries.privileges = self.__privileges
elif name == "roles":
self.__roles = {}
self.__roles["inband"] = { "query": self.__inband, "query2": self.__inband2, "condition": self.__conditionInband, "condition2": self.__conditionInband2 }
self.__roles["blind"] = { "query": self.__blind, "query2": self.__blind2,
"count": self.__count, "count2": self.__count2 }
self.__queries.roles = self.__roles
elif name == "dbs":
self.__dbs = {}
self.__dbs["inband"] = { "query": self.__inband, "query2": self.__inband2 }
self.__dbs["blind"] = { "query": self.__blind, "query2": self.__blind2,
"count": self.__count, "count2": self.__count2 }
self.__queries.dbs = self.__dbs
elif name == "tables":
self.__tables = {}
self.__tables["inband"] = { "query": self.__inband, "condition": self.__conditionInband }
self.__tables["blind"] = { "query": self.__blind, "count": self.__count }
self.__queries.tables = self.__tables
elif name == "columns":
self.__columns = {}
self.__columns["inband"] = { "query": self.__inband, "condition": self.__conditionInband }
self.__columns["blind"] = { "query": self.__blind, "query2": self.__blind2, "count": self.__count, "condition": self.__conditionBlind }
self.__queries.columns = self.__columns
elif name == "dump_table":
self.__dumpTable = {}
self.__dumpTable["inband"] = { "query": self.__inband }
self.__dumpTable["blind"] = { "query": self.__blind, "count": self.__count }
self.__queries.dumpTable = self.__dumpTable
elif name == "search_db":
self.__searchDb = {}
self.__searchDb["inband"] = { "query": self.__inband, "query2": self.__inband2, "condition": self.__conditionInband, "condition2": self.__conditionInband2 }
self.__searchDb["blind"] = { "query": self.__blind, "query2": self.__blind2, "count": self.__count, "count2": self.__count2, "condition": self.__conditionBlind, "condition2": self.__conditionBlind2 }
self.__queries.searchDb = self.__searchDb
elif name == "search_table":
self.__searchTable = {}
self.__searchTable["inband"] = { "query": self.__inband, "query2": self.__inband2, "condition": self.__conditionInband, "condition2": self.__conditionInband2 }
self.__searchTable["blind"] = { "query": self.__blind, "query2": self.__blind2, "count": self.__count, "count2": self.__count2, "condition": self.__conditionBlind, "condition2": self.__conditionBlind2 }
self.__queries.searchTable = self.__searchTable
elif name == "search_column":
self.__searchColumn = {}
self.__searchColumn["inband"] = { "query": self.__inband, "query2": self.__inband2, "condition": self.__conditionInband, "condition2": self.__conditionInband2 }
self.__searchColumn["blind"] = { "query": self.__blind, "query2": self.__blind2, "count": self.__count, "count2": self.__count2, "condition": self.__conditionBlind, "condition2": self.__conditionBlind2 }
self.__queries.searchColumn = self.__searchColumn
def queriesParser():
"""
This function calls a class to parse the default DBMS queries
from an XML file
"""
debugMsg = "parsing XML queries file"
logger.debug(debugMsg)
xmlfile = paths.QUERIES_XML
checkFile(xmlfile)
handler = queriesHandler()
parseXmlFile(xmlfile, handler)

View File

@@ -96,8 +96,7 @@ def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, r
advantage of an blind SQL injection vulnerability on the affected
parameter through a bisection algorithm.
"""
query = agent.prefixQuery(" %s" % queries[kb.misc.testedDbms].inference)
query = agent.prefixQuery(" %s" % queries[kb.misc.testedDbms].inference.query)
query = agent.postfixQuery(query)
payload = agent.payload(newValue=query)
count = None
@@ -139,13 +138,13 @@ def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, r
# NOTE: I assume that only queries that get data from a table
# can return multiple entries
if fromUser and " FROM " in expression:
limitRegExp = re.search(queries[kb.dbms].limitregexp, expression, re.I)
limitRegExp = re.search(queries[kb.dbms].limitregexp.query, expression, re.I)
topLimit = re.search("TOP\s+([\d]+)\s+", expression, re.I)
if limitRegExp or ( kb.dbms == "Microsoft SQL Server" and topLimit ):
if kb.dbms in ( "MySQL", "PostgreSQL" ):
limitGroupStart = queries[kb.dbms].limitgroupstart
limitGroupStop = queries[kb.dbms].limitgroupstop
limitGroupStart = queries[kb.dbms].limitgroupstart.query
limitGroupStop = queries[kb.dbms].limitgroupstop.query
if limitGroupStart.isdigit():
startLimit = int(limitRegExp.group(int(limitGroupStart)))
@@ -155,8 +154,8 @@ def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, r
elif kb.dbms == "Microsoft SQL Server":
if limitRegExp:
limitGroupStart = queries[kb.dbms].limitgroupstart
limitGroupStop = queries[kb.dbms].limitgroupstop
limitGroupStart = queries[kb.dbms].limitgroupstart.query
limitGroupStop = queries[kb.dbms].limitgroupstop.query
if limitGroupStart.isdigit():
startLimit = int(limitRegExp.group(int(limitGroupStart)))
@@ -184,7 +183,7 @@ def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, r
# (or similar, depending on the back-end DBMS) word
if kb.dbms in ( "MySQL", "PostgreSQL" ):
stopLimit += startLimit
untilLimitChar = expression.index(queries[kb.dbms].limitstring)
untilLimitChar = expression.index(queries[kb.dbms].limitstring.query)
expression = expression[:untilLimitChar]
elif kb.dbms == "Microsoft SQL Server":
@@ -202,7 +201,7 @@ def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, r
if not test or test[0] in ("y", "Y"):
# Count the number of SQL query entries output
countFirstField = queries[kb.dbms].count % expressionFieldsList[0]
countFirstField = queries[kb.dbms].count.query % expressionFieldsList[0]
countedExpression = expression.replace(expressionFields, countFirstField, 1)
if re.search(" ORDER BY ", expression, re.I):
@@ -398,7 +397,7 @@ def goStacked(expression, silent=False):
debugMsg = "query: %s" % expression
logger.debug(debugMsg)
comment = queries[kb.dbms].comment
comment = queries[kb.dbms].comment.query
query = agent.prefixQuery("; %s" % expression)
query = agent.postfixQuery("%s;%s" % (query, comment))
payload = agent.payload(newValue=query)

View File

@@ -461,7 +461,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
# check it via equal against the substring-query output
if commonPattern is not None:
# Substring-query containing equals commonPattern
subquery = queries[kb.dbms].substring % (expressionUnescaped, 1, len(commonPattern))
subquery = queries[kb.dbms].substring.query % (expressionUnescaped, 1, len(commonPattern))
testValue = unescaper.unescape("'%s'" % commonPattern) if "'" not in commonPattern else unescaper.unescape("%s" % commonPattern, quote=False)
query = agent.prefixQuery(" %s" % safeStringFormat("AND (%s) = %s", (subquery, testValue)))
query = agent.postfixQuery(query)

View File

@@ -30,7 +30,7 @@ def errorTest():
logger.info(infoMsg)
randInt = getUnicode(randomInt(1))
query = queries[kb.dbms].case % ("%s=%s" % (randInt, randInt))
query = queries[kb.dbms].case.query % ("%s=%s" % (randInt, randInt))
result = inject.goError(query)
if result:

View File

@@ -30,14 +30,15 @@ from lib.core.settings import ERROR_EMPTY_CHAR
from lib.core.settings import ERROR_START_CHAR
from lib.core.settings import ERROR_END_CHAR
def errorUse(expression, resumeValue=True):
def errorUse(expression):
"""
Retrieve the output of a SQL query taking advantage of an error SQL
injection vulnerability on the affected parameter.
"""
output = None
logic = conf.logic
randInt = randomInt(1)
query = agent.prefixQuery(" %s" % queries[kb.misc.testedDbms].error)
query = agent.prefixQuery(" %s" % queries[kb.misc.testedDbms].error.query)
query = agent.postfixQuery(query)
payload = agent.payload(newValue=query)
startLimiter = ""
@@ -45,14 +46,6 @@ def errorUse(expression, resumeValue=True):
expressionUnescaped = expression
if resumeValue:
output = resume(expression, payload)
else:
output = None
if output:
return output
if kb.dbmsDetected:
_, _, _, _, _, _, fieldToCastStr = agent.getFields(expression)
nulledCastedField = agent.nullAndCastField(fieldToCastStr)

View File

@@ -203,7 +203,7 @@ def unionTest():
value = None
columns = None
for comment in (queries[kb.dbms].comment, ""):
for comment in (queries[kb.dbms].comment.query, ""):
if conf.uTech == "orderby":
columns = __unionTestByOrderBy(comment)
else:

View File

@@ -65,12 +65,12 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False, nullCh
# NOTE: I assume that only queries that get data from a table can
# return multiple entries
if " FROM " in expression:
limitRegExp = re.search(queries[kb.dbms].limitregexp, expression, re.I)
limitRegExp = re.search(queries[kb.dbms].limitregexp.query, expression, re.I)
if limitRegExp:
if kb.dbms in ( "MySQL", "PostgreSQL" ):
limitGroupStart = queries[kb.dbms].limitgroupstart
limitGroupStop = queries[kb.dbms].limitgroupstop
limitGroupStart = queries[kb.dbms].limitgroupstart.query
limitGroupStop = queries[kb.dbms].limitgroupstop.query
if limitGroupStart.isdigit():
startLimit = int(limitRegExp.group(int(limitGroupStart)))
@@ -79,8 +79,8 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False, nullCh
limitCond = int(stopLimit) > 1
elif kb.dbms == "Microsoft SQL Server":
limitGroupStart = queries[kb.dbms].limitgroupstart
limitGroupStop = queries[kb.dbms].limitgroupstop
limitGroupStart = queries[kb.dbms].limitgroupstart.query
limitGroupStop = queries[kb.dbms].limitgroupstop.query
if limitGroupStart.isdigit():
startLimit = int(limitRegExp.group(int(limitGroupStart)))
@@ -104,7 +104,7 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False, nullCh
# (or similar, depending on the back-end DBMS) word
if kb.dbms in ( "MySQL", "PostgreSQL" ):
stopLimit += startLimit
untilLimitChar = expression.index(queries[kb.dbms].limitstring)
untilLimitChar = expression.index(queries[kb.dbms].limitstring.query)
expression = expression[:untilLimitChar]
elif kb.dbms == "Microsoft SQL Server":
@@ -123,7 +123,7 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False, nullCh
if test:
# Count the number of SQL query entries output
countFirstField = queries[kb.dbms].count % expressionFieldsList[0]
countFirstField = queries[kb.dbms].count.query % expressionFieldsList[0]
countedExpression = origExpr.replace(expressionFields, countFirstField, 1)
if re.search(" ORDER BY ", expression, re.I):

View File

@@ -14,6 +14,7 @@ from lib.core.common import calculateDeltaSeconds
from lib.core.common import dataToSessionFile
from lib.core.common import safeStringFormat
from lib.core.common import randomStr
from lib.core.common import replaceNewlineTabs
from lib.core.common import restoreDumpMarkedChars
from lib.core.data import conf
from lib.core.data import kb
@@ -30,7 +31,7 @@ def queryOutputLength(expression, payload):
Returns the query output length.
"""
lengthQuery = queries[kb.dbms].length
lengthQuery = queries[kb.dbms].length.query
select = re.search("\ASELECT\s+", expression, re.I)
selectTopExpr = re.search("\ASELECT\s+TOP\s+[\d]+\s+(.+?)\s+FROM", expression, re.I)
@@ -83,7 +84,7 @@ def queryOutputLength(expression, payload):
if length == " ":
length = 0
return count, length, regExpr
def resume(expression, payload):
@@ -141,7 +142,7 @@ def resume(expression, payload):
if not kb.dbms:
return None
substringQuery = queries[kb.dbms].substring
substringQuery = queries[kb.dbms].substring.query
select = re.search("\ASELECT ", expression, re.I)
_, length, regExpr = queryOutputLength(expression, payload)