mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2025-04-07 10:44:19 +03:00
Properly deal with partial (single entry) UNION injections.
Got rid of kb.union*, now it's all stored/used from kb.injection. Minor bug fix with where=2 detection phase.
This commit is contained in:
parent
d7a7993e0d
commit
af9725214a
|
@ -378,8 +378,12 @@ def checkSqlInjection(place, parameter, value):
|
|||
|
||||
# In case of UNION query SQL injection
|
||||
elif method == PAYLOAD.METHOD.UNION:
|
||||
# Test for UNION injection and set the sample
|
||||
# payload as well as the vector.
|
||||
# NOTE: vector is set to a tuple with 6 elements,
|
||||
# used afterwards by Agent.forgeInbandQuery()
|
||||
# method to forge the UNION query payload
|
||||
configUnion(test.request.char, test.request.columns)
|
||||
|
||||
dbmsToUnescape = dbms if dbms is not None else injection.dbms
|
||||
reqPayload, vector = unionTest(comment, place, parameter, value, prefix, suffix, dbmsToUnescape)
|
||||
|
||||
|
@ -389,6 +393,10 @@ def checkSqlInjection(place, parameter, value):
|
|||
|
||||
injectable = True
|
||||
|
||||
# Overwrite 'where' because it can differ
|
||||
# in unionTest()'s vector (1 or 2)
|
||||
where = vector[5]
|
||||
|
||||
# If the injection test was successful feed the injection
|
||||
# object with the test's details
|
||||
if injectable is True:
|
||||
|
|
|
@ -1164,7 +1164,6 @@ def __setKnowledgeBaseAttributes(flushAll=True):
|
|||
kb.threadContinue = True
|
||||
kb.threadException = False
|
||||
kb.threadData = {}
|
||||
kb.unionNegative = False
|
||||
|
||||
if flushAll:
|
||||
kb.keywords = set(getFileItems(paths.SQL_KEYWORDS))
|
||||
|
|
|
@ -191,10 +191,6 @@ def setOs():
|
|||
if condition:
|
||||
dataToSessionFile("[%s][%s][%s][OS][%s]\n" % (conf.url, kb.injection.place, safeFormatString(conf.parameters[kb.injection.place]), safeFormatString(kb.os)))
|
||||
|
||||
def setUnion(negative=False):
|
||||
if negative:
|
||||
kb.unionNegative = True
|
||||
|
||||
def setRemoteTempPath():
|
||||
condition = (
|
||||
not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
|
||||
|
|
|
@ -425,9 +425,6 @@ def getValue(expression, blind=True, inband=True, error=True, time=True, fromUse
|
|||
count += 1
|
||||
found = (value is not None) or (value is None and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE
|
||||
|
||||
oldUnionNegative = kb.unionNegative
|
||||
kb.unionNegative = False
|
||||
|
||||
if error and isTechniqueAvailable(PAYLOAD.TECHNIQUE.ERROR) and not found:
|
||||
kb.technique = PAYLOAD.TECHNIQUE.ERROR
|
||||
|
||||
|
@ -461,8 +458,6 @@ def getValue(expression, blind=True, inband=True, error=True, time=True, fromUse
|
|||
else:
|
||||
value = __goInferenceProxy(query, fromUser, expected, batch, resumeValue, unpack, charsetType, firstChar, lastChar)
|
||||
|
||||
kb.unionNegative = oldUnionNegative
|
||||
|
||||
if value and isinstance(value, basestring):
|
||||
value = value.strip()
|
||||
else:
|
||||
|
|
|
@ -21,14 +21,13 @@ from lib.core.data import logger
|
|||
from lib.core.data import queries
|
||||
from lib.core.enums import DBMS
|
||||
from lib.core.enums import PAYLOAD
|
||||
from lib.core.session import setUnion
|
||||
from lib.core.unescaper import unescaper
|
||||
from lib.parse.html import htmlParser
|
||||
from lib.request.connect import Connect as Request
|
||||
|
||||
def __unionPosition(comment, place, parameter, value, prefix, suffix, dbms, count, where=1):
|
||||
validPayload = None
|
||||
unionVector = None
|
||||
vector = None
|
||||
|
||||
# For each column of the table (# of NULL) perform a request using
|
||||
# the UNION ALL SELECT statement to test it the target url is
|
||||
|
@ -48,7 +47,7 @@ def __unionPosition(comment, place, parameter, value, prefix, suffix, dbms, coun
|
|||
|
||||
if resultPage and randQuery in resultPage and " UNION ALL SELECT " not in resultPage:
|
||||
validPayload = payload
|
||||
unionVector = (exprPosition, count, comment, prefix, suffix)
|
||||
vector = (exprPosition, count, comment, prefix, suffix, where)
|
||||
|
||||
if where == 1:
|
||||
# Prepare expression with delimiters
|
||||
|
@ -64,34 +63,26 @@ def __unionPosition(comment, place, parameter, value, prefix, suffix, dbms, coun
|
|||
resultPage, _ = Request.queryPage(payload, place=place, content=True)
|
||||
|
||||
if resultPage and (randQuery not in resultPage or randQuery2 not in resultPage):
|
||||
setUnion(negative=True)
|
||||
vector = (exprPosition, count, comment, prefix, suffix, 2)
|
||||
|
||||
break
|
||||
|
||||
return validPayload, unionVector
|
||||
return validPayload, vector
|
||||
|
||||
def __unionConfirm(comment, place, parameter, value, prefix, suffix, dbms, count):
|
||||
validPayload = None
|
||||
unionVector = None
|
||||
vector = None
|
||||
|
||||
# Confirm the inband SQL injection and get the exact column
|
||||
# position which can be used to extract data
|
||||
validPayload, unionVector = __unionPosition(comment, place, parameter, value, prefix, suffix, dbms, count)
|
||||
validPayload, vector = __unionPosition(comment, place, parameter, value, prefix, suffix, dbms, count)
|
||||
|
||||
# Assure that the above function found the exploitable full inband
|
||||
# SQL injection position
|
||||
if not validPayload:
|
||||
validPayload, unionVector = __unionPosition(comment, place, parameter, value, prefix, suffix, dbms, count, where=2)
|
||||
validPayload, vector = __unionPosition(comment, place, parameter, value, prefix, suffix, dbms, count, where=2)
|
||||
|
||||
# Assure that the above function found the exploitable partial
|
||||
# (single entry) inband SQL injection position with negative
|
||||
# parameter validPayload
|
||||
if not validPayload:
|
||||
return None, None
|
||||
else:
|
||||
setUnion(negative=True)
|
||||
|
||||
return validPayload, unionVector
|
||||
return validPayload, vector
|
||||
|
||||
def __unionTestByCharBruteforce(comment, place, parameter, value, prefix, suffix, dbms):
|
||||
"""
|
||||
|
@ -101,7 +92,7 @@ def __unionTestByCharBruteforce(comment, place, parameter, value, prefix, suffix
|
|||
"""
|
||||
|
||||
validPayload = None
|
||||
unionVector = None
|
||||
vector = None
|
||||
query = agent.prefixQuery("UNION ALL SELECT %s" % conf.uChar)
|
||||
|
||||
for count in range(conf.uColsStart, conf.uColsStop+1):
|
||||
|
@ -118,14 +109,14 @@ def __unionTestByCharBruteforce(comment, place, parameter, value, prefix, suffix
|
|||
debugMsg = "testing number of columns: %s" % status
|
||||
logger.debug(debugMsg)
|
||||
|
||||
validPayload, unionVector = __unionConfirm(comment, place, parameter, value, prefix, suffix, dbms, count)
|
||||
validPayload, vector = __unionConfirm(comment, place, parameter, value, prefix, suffix, dbms, count)
|
||||
|
||||
if validPayload:
|
||||
break
|
||||
|
||||
clearConsoleLine(True)
|
||||
|
||||
return validPayload, unionVector
|
||||
return validPayload, vector
|
||||
|
||||
def unionTest(comment, place, parameter, value, prefix, suffix, dbms):
|
||||
"""
|
||||
|
@ -138,9 +129,9 @@ def unionTest(comment, place, parameter, value, prefix, suffix, dbms):
|
|||
|
||||
oldTechnique = kb.technique
|
||||
kb.technique = PAYLOAD.TECHNIQUE.UNION
|
||||
validPayload, unionVector = __unionTestByCharBruteforce(comment, place, parameter, value, prefix, suffix, dbms)
|
||||
validPayload, vector = __unionTestByCharBruteforce(comment, place, parameter, value, prefix, suffix, dbms)
|
||||
|
||||
if validPayload:
|
||||
validPayload = agent.removePayloadDelimiters(validPayload, False)
|
||||
|
||||
return validPayload, unionVector
|
||||
return validPayload, vector
|
||||
|
|
|
@ -56,7 +56,7 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False, nullCh
|
|||
expression = agent.concatQuery(expression, unpack)
|
||||
expression = unescaper.unescape(expression)
|
||||
|
||||
if kb.unionNegative and not direct:
|
||||
if kb.injection.data[PAYLOAD.TECHNIQUE.UNION].where == 2 and not direct:
|
||||
_, _, _, _, _, expressionFieldsList, expressionFields = agent.getFields(origExpr)
|
||||
|
||||
# We have to check if the SQL query might return multiple entries
|
||||
|
@ -194,6 +194,8 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False, nullCh
|
|||
status = '%d/%d entries (%d%s)' % (count, length, round(100.0*count/length), '%')
|
||||
dataToStdout("\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), status), True)
|
||||
|
||||
dataToStdout("\n")
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print
|
||||
warnMsg = "Ctrl+C detected in dumping phase"
|
||||
|
|
Loading…
Reference in New Issue
Block a user