One more step to fully working UNION exploitation after merge into detection phase

This commit is contained in:
Bernardo Damele 2011-01-12 01:13:32 +00:00
parent b5c6f7556f
commit 8a67aea754
9 changed files with 38 additions and 85 deletions

View File

@ -473,7 +473,7 @@ class Agent:
return concatenatedQuery
def forgeInbandQuery(self, query, exprPosition=None, nullChar=None, count=None, comment=None, prefix=None, suffix=None, multipleUnions=None):
def forgeInbandQuery(self, query, exprPosition=None, count=None, comment=None, prefix=None, suffix=None, multipleUnions=None):
"""
Take in input an query (pseudo query) string and return its
processed UNION ALL SELECT query.
@ -504,15 +504,6 @@ class Agent:
@rtype: C{str}
"""
if nullChar is None:
nullChar = conf.uChar
if count is None:
count = kb.unionCount
if comment is None:
comment = kb.unionComment
if query.startswith("SELECT "):
query = query[len("SELECT "):]
@ -523,9 +514,6 @@ class Agent:
query = query[len("TOP %s " % topNum):]
inbandQuery += "TOP %s " % topNum
if not isinstance(exprPosition, int):
exprPosition = kb.unionPosition
intoRegExp = re.search("(\s+INTO (DUMP|OUT)FILE\s+\'(.+?)\')", query, re.I)
if intoRegExp:
@ -546,7 +534,7 @@ class Agent:
else:
inbandQuery += query
else:
inbandQuery += nullChar
inbandQuery += conf.uChar
if " FROM " in query and not query.startswith("SELECT ") and "(CASE WHEN (" not in query:
conditionIndex = query.index(" FROM ")
@ -569,7 +557,7 @@ class Agent:
if element == exprPosition:
inbandQuery += multipleUnions
else:
inbandQuery += nullChar
inbandQuery += conf.uChar
if kb.dbms == DBMS.ORACLE:
inbandQuery += " FROM DUAL"

View File

@ -1109,9 +1109,6 @@ def __setKnowledgeBaseAttributes(flushAll=True):
kb.data = advancedDict()
# Old style injection flag
kb.unionTest = None
# Basic back-end DBMS fingerprint
kb.dbms = None
kb.dbmsDetected = False
@ -1167,9 +1164,6 @@ def __setKnowledgeBaseAttributes(flushAll=True):
kb.threadContinue = True
kb.threadException = False
kb.threadData = {}
kb.unionComment = ""
kb.unionCount = None
kb.unionPosition = None
kb.unionNegative = False
if flushAll:

View File

@ -191,27 +191,7 @@ 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(comment=None, count=None, position=None, negative=False, char=None, payload=None):
"""
@param comment: union comment to save in session file
@type comment: C{str}
@param count: union count to save in session file
@type count: C{str}
@param position: union position to save in session file
@type position: C{str}
"""
if comment:
kb.unionComment = comment
if count:
kb.unionCount = count
if position is not None:
kb.unionPosition = position
def setUnion(negative=False):
if negative:
kb.unionNegative = True

View File

@ -30,9 +30,6 @@ def __unionPosition(comment, place, parameter, value, prefix, suffix, dbms, coun
validPayload = None
unionVector = None
if count is None:
count = kb.unionCount
# For each column of the table (# of NULL) perform a request using
# the UNION ALL SELECT statement to test it the target url is
# affected by an exploitable inband SQL injection vulnerability
@ -50,9 +47,8 @@ def __unionPosition(comment, place, parameter, value, prefix, suffix, dbms, coun
resultPage, _ = Request.queryPage(payload, place=place, content=True)
if resultPage and randQuery in resultPage and " UNION ALL SELECT " not in resultPage:
setUnion(position=exprPosition)
validPayload = payload
unionVector = agent.forgeInbandQuery("[QUERY]", exprPosition, count=count, comment=comment, prefix=prefix, suffix=suffix)
unionVector = (exprPosition, count, comment, prefix, suffix)
if where == 1:
# Prepare expression with delimiters
@ -80,18 +76,17 @@ def __unionConfirm(comment, place, parameter, value, prefix, suffix, dbms, count
# Confirm the inband SQL injection and get the exact column
# position which can be used to extract data
if not isinstance(kb.unionPosition, int):
validPayload, unionVector = __unionPosition(comment, place, parameter, value, prefix, suffix, dbms, count)
# Assure that the above function found the exploitable full inband
# SQL injection position
if not isinstance(kb.unionPosition, int):
if not validPayload:
validPayload, unionVector = __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 isinstance(kb.unionPosition, int):
if not validPayload:
return None, None
else:
setUnion(negative=True)
@ -126,7 +121,6 @@ def __unionTestByCharBruteforce(comment, place, parameter, value, prefix, suffix
validPayload, unionVector = __unionConfirm(comment, place, parameter, value, prefix, suffix, dbms, count)
if validPayload:
setUnion(count=count)
break
clearConsoleLine(True)
@ -148,8 +142,5 @@ def unionTest(comment, place, parameter, value, prefix, suffix, dbms):
if validPayload:
validPayload = agent.removePayloadDelimiters(validPayload, False)
setUnion(char=conf.uChar)
setUnion(comment=comment)
setUnion(payload=validPayload)
return validPayload, unionVector

View File

@ -51,9 +51,6 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False, nullCh
if resetCounter:
reqCount = 0
if not kb.unionCount:
return
# Prepare expression with delimiters
if unescape:
expression = agent.concatQuery(expression, unpack)
@ -211,8 +208,8 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False, nullCh
else:
# Forge the inband SQL injection request
query = unescaper.unescape(expression)
query = agent.cleanupPayload(kb.injection.data[PAYLOAD.TECHNIQUE.UNION].vector, query=query)
vector = kb.injection.data[PAYLOAD.TECHNIQUE.UNION].vector
query = agent.forgeInbandQuery(expression, exprPosition=vector[0], count=vector[1], comment=vector[2], prefix=vector[3], suffix=vector[4])
payload = agent.payload(newValue=query)
# Perform the request

View File

@ -11,6 +11,7 @@ from lib.core.agent import agent
from lib.core.common import arrayizeValue
from lib.core.common import getRange
from lib.core.common import isNumPosStrValue
from lib.core.common import isTechniqueAvailable
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
@ -52,7 +53,7 @@ class Enumeration(GenericEnumeration):
else:
dbs = [conf.db]
if kb.unionPosition is not None or conf.direct:
if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct:
for db in dbs:
if conf.excludeSysDbs and db in self.excludeDbsList:
infoMsg = "skipping system database '%s'" % db
@ -142,7 +143,7 @@ class Enumeration(GenericEnumeration):
continue
if kb.unionPosition is not None or conf.direct:
if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct:
query = rootQuery.inband.query % db
query += tblQuery
values = inject.getValue(query, blind=False, error=False)
@ -227,7 +228,7 @@ class Enumeration(GenericEnumeration):
continue
if kb.unionPosition is not None or conf.direct:
if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct:
query = rootQuery.inband.query % (db, db, db, db, db)
query += " AND %s" % colQuery.replace("[DB]", db)
values = inject.getValue(query, blind=False, error=False)

View File

@ -13,6 +13,7 @@ import os
from lib.core.common import getRange
from lib.core.common import isNumPosStrValue
from lib.core.common import isTechniqueAvailable
from lib.core.common import posixToNtSlashes
from lib.core.common import randomStr
from lib.core.data import conf
@ -91,7 +92,7 @@ class Filesystem(GenericFilesystem):
binToHexQuery = binToHexQuery.replace(" ", "").replace("\n", " ")
inject.goStacked(binToHexQuery)
if kb.unionPosition is not None:
if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION):
result = inject.getValue("SELECT %s FROM %s ORDER BY id ASC" % (self.tblField, hexTbl), sort=False, resumeValue=False, blind=False, error=False)
if not result:

View File

@ -10,6 +10,7 @@ See the file 'doc/COPYING' for copying permission
from lib.core.agent import agent
from lib.core.common import getRange
from lib.core.common import isNumPosStrValue
from lib.core.common import isTechniqueAvailable
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
@ -39,7 +40,7 @@ class Enumeration(GenericEnumeration):
# Set containing the list of DBMS administrators
areAdmins = set()
if kb.unionPosition is not None or conf.direct:
if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct:
if query2:
query = rootQuery.inband.query2
condition = rootQuery.inband.condition2
@ -199,7 +200,7 @@ class Enumeration(GenericEnumeration):
colQuery = colQuery % column
for db in dbs.keys():
if kb.unionPosition is not None or conf.direct:
if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct:
query = rootQuery.inband.query
query += colQuery
values = inject.getValue(query, blind=False, error=False)

View File

@ -151,7 +151,7 @@ class Enumeration:
condition = ( kb.dbms == DBMS.MSSQL and kb.dbmsVersion[0] in ( "2005", "2008" ) )
condition |= ( kb.dbms == DBMS.MYSQL and not kb.data.has_information_schema )
if kb.unionPosition is not None or conf.direct:
if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct:
if condition:
query = rootQuery.inband.query2
else:
@ -210,7 +210,7 @@ class Enumeration:
logger.info(infoMsg)
if kb.unionPosition is not None or conf.direct:
if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct:
if kb.dbms == DBMS.MSSQL and kb.dbmsVersion[0] in ( "2005", "2008" ):
query = rootQuery.inband.query2
else:
@ -431,7 +431,7 @@ class Enumeration:
"E": "EXECUTE"
}
if kb.unionPosition is not None or conf.direct:
if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct:
if kb.dbms == DBMS.MYSQL and not kb.data.has_information_schema:
query = rootQuery.inband.query2
condition = rootQuery.inband.condition2
@ -677,7 +677,7 @@ class Enumeration:
rootQuery = queries[kb.dbms].dbs
if kb.unionPosition is not None or conf.direct:
if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct:
if kb.dbms == DBMS.MYSQL and not kb.data.has_information_schema:
query = rootQuery.inband.query2
else:
@ -784,7 +784,7 @@ class Enumeration:
else:
dbs = kb.data.cachedDbs
if kb.unionPosition is not None or conf.direct:
if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct:
query = rootQuery.inband.query
condition = rootQuery.inband.condition if 'condition' in rootQuery.inband else None
@ -977,7 +977,7 @@ class Enumeration:
infoMsg += "on database '%s'" % conf.db
logger.info(infoMsg)
if kb.unionPosition is not None or conf.direct:
if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct:
if kb.dbms in ( DBMS.MYSQL, DBMS.PGSQL ):
query = rootQuery.inband.query % (conf.tbl, conf.db)
query += condQuery
@ -1174,7 +1174,7 @@ class Enumeration:
entriesCount = 0
if kb.unionPosition is not None or conf.direct:
if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct:
if kb.dbms == DBMS.ORACLE:
query = rootQuery.inband.query % (colString, conf.tbl.upper())
elif kb.dbms == DBMS.SQLITE:
@ -1516,7 +1516,7 @@ class Enumeration:
dbQuery = "%s%s" % (dbCond, dbCondParam)
dbQuery = dbQuery % db
if kb.unionPosition is not None or conf.direct:
if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct:
if kb.dbms == DBMS.MYSQL and not kb.data.has_information_schema:
query = rootQuery.inband.query2
else:
@ -1624,7 +1624,7 @@ class Enumeration:
tblQuery = "%s%s" % (tblCond, tblCondParam)
tblQuery = tblQuery % tbl
if kb.unionPosition is not None or conf.direct:
if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct:
query = rootQuery.inband.query
query += tblQuery
query += exclDbsQuery
@ -1774,7 +1774,7 @@ class Enumeration:
colQuery = "%s%s" % (colCond, colCondParam)
colQuery = colQuery % column
if kb.unionPosition is not None or conf.direct:
if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct:
query = rootQuery.inband.query
query += colQuery
query += exclDbsQuery