Major bug fix.

Minor code refactoring.
This commit is contained in:
Bernardo Damele 2011-01-16 01:17:09 +00:00
parent c0d5daee99
commit 0fc4ebdc1b
4 changed files with 24 additions and 32 deletions

View File

@ -72,11 +72,13 @@ def unescapeDbms(payload, injection, dbms):
# provided a DBMS (conf.dbms), unescape the strings between single # provided a DBMS (conf.dbms), unescape the strings between single
# quotes in the payload # quotes in the payload
if injection.dbms is not None: if injection.dbms is not None:
payload = unescape(payload, injection.dbms) payload = unescape(payload, dbms=injection.dbms)
elif dbms is not None: elif dbms is not None:
payload = unescape(payload, dbms) payload = unescape(payload, dbms=dbms)
elif conf.dbms is not None: elif conf.dbms is not None:
payload = unescape(payload, conf.dbms) payload = unescape(payload, dbms=conf.dbms)
elif getIdentifiedDBMS() is not None:
payload = unescape(payload, dbms=getIdentifiedDBMS())
return payload return payload
@ -387,8 +389,7 @@ def checkSqlInjection(place, parameter, value):
logger.warn(warnMsg) logger.warn(warnMsg)
configUnion(test.request.char, test.request.columns) configUnion(test.request.char, test.request.columns)
dbmsToUnescape = kb.misc.fpDbms if kb.misc.fpDbms is not None else injection.dbms reqPayload, vector = unionTest(comment, place, parameter, value, prefix, suffix)
reqPayload, vector = unionTest(comment, place, parameter, value, prefix, suffix, dbmsToUnescape)
if isinstance(reqPayload, basestring): if isinstance(reqPayload, basestring):
infoMsg = "%s parameter '%s' is '%s' injectable" % (place, parameter, title) infoMsg = "%s parameter '%s' is '%s' injectable" % (place, parameter, title)

View File

@ -422,26 +422,20 @@ class Agent:
fieldsSelectFrom, fieldsSelect, fieldsNoSelect, fieldsSelectTop, fieldsSelectCase, _, fieldsToCastStr = self.getFields(query) fieldsSelectFrom, fieldsSelect, fieldsNoSelect, fieldsSelectTop, fieldsSelectCase, _, fieldsToCastStr = self.getFields(query)
if getIdentifiedDBMS() == DBMS.MYSQL: if getIdentifiedDBMS() == DBMS.MYSQL:
if fieldsSelectCase: if fieldsSelectFrom:
concatenatedQuery = concatenatedQuery.replace("SELECT ", "CONCAT('%s'," % kb.misc.start, 1)
concatenatedQuery += ",'%s')" % kb.misc.stop
elif fieldsSelectFrom:
concatenatedQuery = concatenatedQuery.replace("SELECT ", "CONCAT('%s'," % kb.misc.start, 1) concatenatedQuery = concatenatedQuery.replace("SELECT ", "CONCAT('%s'," % kb.misc.start, 1)
concatenatedQuery = concatenatedQuery.replace(" FROM ", ",'%s') FROM " % kb.misc.stop, 1) concatenatedQuery = concatenatedQuery.replace(" FROM ", ",'%s') FROM " % kb.misc.stop, 1)
elif fieldsSelect: elif (fieldsSelect, fieldsSelectCase):
concatenatedQuery = concatenatedQuery.replace("SELECT ", "CONCAT('%s'," % kb.misc.start, 1) concatenatedQuery = concatenatedQuery.replace("SELECT ", "CONCAT('%s'," % kb.misc.start, 1)
concatenatedQuery += ",'%s')" % kb.misc.stop concatenatedQuery += ",'%s')" % kb.misc.stop
elif fieldsNoSelect: elif fieldsNoSelect:
concatenatedQuery = "CONCAT('%s',%s,'%s')" % (kb.misc.start, concatenatedQuery, kb.misc.stop) concatenatedQuery = "CONCAT('%s',%s,'%s')" % (kb.misc.start, concatenatedQuery, kb.misc.stop)
elif getIdentifiedDBMS() in ( DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE ): elif getIdentifiedDBMS() in ( DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE ):
if fieldsSelectCase: if fieldsSelectFrom:
concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'||" % kb.misc.start, 1)
concatenatedQuery += "||'%s'" % kb.misc.stop
elif fieldsSelectFrom:
concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'||" % kb.misc.start, 1) concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'||" % kb.misc.start, 1)
concatenatedQuery = concatenatedQuery.replace(" FROM ", "||'%s' FROM " % kb.misc.stop, 1) concatenatedQuery = concatenatedQuery.replace(" FROM ", "||'%s' FROM " % kb.misc.stop, 1)
elif fieldsSelect: elif (fieldsSelect, fieldsSelectCase):
concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'||" % kb.misc.start, 1) concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'||" % kb.misc.start, 1)
concatenatedQuery += "||'%s'" % kb.misc.stop concatenatedQuery += "||'%s'" % kb.misc.stop
elif fieldsNoSelect: elif fieldsNoSelect:
@ -455,13 +449,10 @@ class Agent:
topNum = re.search("\ASELECT\s+TOP\s+([\d]+)\s+", concatenatedQuery, re.I).group(1) topNum = re.search("\ASELECT\s+TOP\s+([\d]+)\s+", concatenatedQuery, re.I).group(1)
concatenatedQuery = concatenatedQuery.replace("SELECT TOP %s " % topNum, "TOP %s '%s'+" % (topNum, kb.misc.start), 1) concatenatedQuery = concatenatedQuery.replace("SELECT TOP %s " % topNum, "TOP %s '%s'+" % (topNum, kb.misc.start), 1)
concatenatedQuery = concatenatedQuery.replace(" FROM ", "+'%s' FROM " % kb.misc.stop, 1) concatenatedQuery = concatenatedQuery.replace(" FROM ", "+'%s' FROM " % kb.misc.stop, 1)
elif fieldsSelectCase:
concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'+" % kb.misc.start, 1)
concatenatedQuery += "+'%s'" % kb.misc.stop
elif fieldsSelectFrom: elif fieldsSelectFrom:
concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'+" % kb.misc.start, 1) concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'+" % kb.misc.start, 1)
concatenatedQuery = concatenatedQuery.replace(" FROM ", "+'%s' FROM " % kb.misc.stop, 1) concatenatedQuery = concatenatedQuery.replace(" FROM ", "+'%s' FROM " % kb.misc.stop, 1)
elif fieldsSelect: elif (fieldsSelect, fieldsSelectCase):
concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'+" % kb.misc.start, 1) concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'+" % kb.misc.start, 1)
concatenatedQuery += "+'%s'" % kb.misc.stop concatenatedQuery += "+'%s'" % kb.misc.stop
elif fieldsNoSelect: elif fieldsNoSelect:
@ -524,7 +515,7 @@ class Agent:
inbandQuery += ", " inbandQuery += ", "
if element == position: if element == position:
if " FROM " in query and "EXISTS(" not in query and not query.startswith("SELECT ") and "(CASE WHEN (" not in query: if " FROM " in query and "EXISTS(" not in query and not query.startswith("SELECT "):
conditionIndex = query.index(" FROM ") conditionIndex = query.index(" FROM ")
inbandQuery += query[:conditionIndex] inbandQuery += query[:conditionIndex]
else: else:
@ -532,7 +523,7 @@ class Agent:
else: else:
inbandQuery += char inbandQuery += char
if " FROM " in query and "EXISTS(" not in query and not query.startswith("SELECT ") and "(CASE WHEN (" not in query: if " FROM " in query and "EXISTS(" not in query and not query.startswith("SELECT "):
conditionIndex = query.index(" FROM ") conditionIndex = query.index(" FROM ")
inbandQuery += query[conditionIndex:] inbandQuery += query[conditionIndex:]

View File

@ -27,7 +27,7 @@ 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
def __unionPosition(comment, place, parameter, value, prefix, suffix, dbms, count, where=1): def __unionPosition(comment, place, parameter, value, prefix, suffix, count, where=1):
validPayload = None validPayload = None
vector = None vector = None
@ -38,7 +38,7 @@ def __unionPosition(comment, place, parameter, value, prefix, suffix, dbms, coun
# Prepare expression with delimiters # Prepare expression with delimiters
randQuery = randomStr() randQuery = randomStr()
randQueryProcessed = agent.concatQuery("\'%s\'" % randQuery) randQueryProcessed = agent.concatQuery("\'%s\'" % randQuery)
randQueryUnescaped = unescaper.unescape(randQueryProcessed, dbms=dbms) randQueryUnescaped = unescaper.unescape(randQueryProcessed)
# Forge the inband SQL injection request # Forge the inband SQL injection request
query = agent.forgeInbandQuery(randQueryUnescaped, position, count, comment, prefix, suffix, conf.uChar) query = agent.forgeInbandQuery(randQueryUnescaped, position, count, comment, prefix, suffix, conf.uChar)
@ -55,7 +55,7 @@ def __unionPosition(comment, place, parameter, value, prefix, suffix, dbms, coun
# Prepare expression with delimiters # Prepare expression with delimiters
randQuery2 = randomStr() randQuery2 = randomStr()
randQueryProcessed2 = agent.concatQuery("\'%s\'" % randQuery2) randQueryProcessed2 = agent.concatQuery("\'%s\'" % randQuery2)
randQueryUnescaped2 = unescaper.unescape(randQueryProcessed2, dbms=dbms) randQueryUnescaped2 = unescaper.unescape(randQueryProcessed2)
# Confirm that it is a full inband SQL injection # Confirm that it is a full inband SQL injection
query = agent.forgeInbandQuery(randQueryUnescaped, position, count, comment, prefix, suffix, conf.uChar, multipleUnions=randQueryUnescaped2) query = agent.forgeInbandQuery(randQueryUnescaped, position, count, comment, prefix, suffix, conf.uChar, multipleUnions=randQueryUnescaped2)
@ -71,22 +71,22 @@ def __unionPosition(comment, place, parameter, value, prefix, suffix, dbms, coun
return validPayload, vector return validPayload, vector
def __unionConfirm(comment, place, parameter, value, prefix, suffix, dbms, count): def __unionConfirm(comment, place, parameter, value, prefix, suffix, count):
validPayload = None validPayload = None
vector = None vector = None
# Confirm the inband SQL injection and get the exact column # Confirm the inband SQL injection and get the exact column
# position which can be used to extract data # position which can be used to extract data
validPayload, vector = __unionPosition(comment, place, parameter, value, prefix, suffix, dbms, count) validPayload, vector = __unionPosition(comment, place, parameter, value, prefix, suffix, count)
# 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 validPayload: if not validPayload:
validPayload, vector = __unionPosition(comment, place, parameter, value, prefix, suffix, dbms, count, where=2) validPayload, vector = __unionPosition(comment, place, parameter, value, prefix, suffix, count, where=2)
return validPayload, vector return validPayload, vector
def __unionTestByCharBruteforce(comment, place, parameter, value, prefix, suffix, dbms): def __unionTestByCharBruteforce(comment, place, parameter, value, prefix, suffix):
""" """
This method tests if the target url is affected by an inband This method tests if the target url is affected by an inband
SQL injection vulnerability. The test is done up to 50 columns SQL injection vulnerability. The test is done up to 50 columns
@ -111,7 +111,7 @@ def __unionTestByCharBruteforce(comment, place, parameter, value, prefix, suffix
debugMsg = "testing %s columns (%d%%)" % (status, round(100.0*count/conf.uColsStop)) debugMsg = "testing %s columns (%d%%)" % (status, round(100.0*count/conf.uColsStop))
logger.debug(debugMsg) logger.debug(debugMsg)
validPayload, vector = __unionConfirm(comment, place, parameter, value, prefix, suffix, dbms, count) validPayload, vector = __unionConfirm(comment, place, parameter, value, prefix, suffix, count)
if validPayload: if validPayload:
break break
@ -120,7 +120,7 @@ def __unionTestByCharBruteforce(comment, place, parameter, value, prefix, suffix
return validPayload, vector return validPayload, vector
def unionTest(comment, place, parameter, value, prefix, suffix, dbms): def unionTest(comment, place, parameter, value, prefix, suffix):
""" """
This method tests if the target url is affected by an inband This method tests if the target url is affected by an inband
SQL injection vulnerability. The test is done up to 3*50 times SQL injection vulnerability. The test is done up to 3*50 times
@ -130,7 +130,7 @@ def unionTest(comment, place, parameter, value, prefix, suffix, dbms):
return return
kb.technique = PAYLOAD.TECHNIQUE.UNION kb.technique = PAYLOAD.TECHNIQUE.UNION
validPayload, vector = __unionTestByCharBruteforce(comment, place, parameter, value, prefix, suffix, dbms) validPayload, vector = __unionTestByCharBruteforce(comment, place, parameter, value, prefix, suffix)
if validPayload: if validPayload:
validPayload = agent.removePayloadDelimiters(validPayload, False) validPayload = agent.removePayloadDelimiters(validPayload, False)

View File

@ -67,7 +67,7 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False, unpack
# entry per time # entry per time
# NOTE: I assume that only queries that get data from a table can # NOTE: I assume that only queries that get data from a table can
# return multiple entries # return multiple entries
if " FROM " in expression and "EXISTS(" not in expression: if " FROM " in expression.upper() and " FROM DUAL" not in expression.upper() and "EXISTS(" not in expression.upper():
limitRegExp = re.search(queries[getIdentifiedDBMS()].limitregexp.query, expression, re.I) limitRegExp = re.search(queries[getIdentifiedDBMS()].limitregexp.query, expression, re.I)
if limitRegExp: if limitRegExp: