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 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 Take in input an query (pseudo query) string and return its
processed UNION ALL SELECT query. processed UNION ALL SELECT query.
@ -504,15 +504,6 @@ class Agent:
@rtype: C{str} @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 "): if query.startswith("SELECT "):
query = query[len("SELECT "):] query = query[len("SELECT "):]
@ -523,9 +514,6 @@ class Agent:
query = query[len("TOP %s " % topNum):] query = query[len("TOP %s " % topNum):]
inbandQuery += "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) intoRegExp = re.search("(\s+INTO (DUMP|OUT)FILE\s+\'(.+?)\')", query, re.I)
if intoRegExp: if intoRegExp:
@ -546,7 +534,7 @@ class Agent:
else: else:
inbandQuery += query inbandQuery += query
else: else:
inbandQuery += nullChar inbandQuery += conf.uChar
if " FROM " in query and not query.startswith("SELECT ") and "(CASE WHEN (" not in query: if " FROM " in query and not query.startswith("SELECT ") and "(CASE WHEN (" not in query:
conditionIndex = query.index(" FROM ") conditionIndex = query.index(" FROM ")
@ -569,7 +557,7 @@ class Agent:
if element == exprPosition: if element == exprPosition:
inbandQuery += multipleUnions inbandQuery += multipleUnions
else: else:
inbandQuery += nullChar inbandQuery += conf.uChar
if kb.dbms == DBMS.ORACLE: if kb.dbms == DBMS.ORACLE:
inbandQuery += " FROM DUAL" inbandQuery += " FROM DUAL"

View File

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

View File

@ -191,27 +191,7 @@ def setOs():
if condition: if condition:
dataToSessionFile("[%s][%s][%s][OS][%s]\n" % (conf.url, kb.injection.place, safeFormatString(conf.parameters[kb.injection.place]), safeFormatString(kb.os))) 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): def setUnion(negative=False):
"""
@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
if negative: if negative:
kb.unionNegative = True kb.unionNegative = True

View File

@ -30,9 +30,6 @@ def __unionPosition(comment, place, parameter, value, prefix, suffix, dbms, coun
validPayload = None validPayload = None
unionVector = None unionVector = None
if count is None:
count = kb.unionCount
# 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
# affected by an exploitable inband SQL injection vulnerability # 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) resultPage, _ = Request.queryPage(payload, place=place, content=True)
if resultPage and randQuery in resultPage and " UNION ALL SELECT " not in resultPage: if resultPage and randQuery in resultPage and " UNION ALL SELECT " not in resultPage:
setUnion(position=exprPosition)
validPayload = payload validPayload = payload
unionVector = agent.forgeInbandQuery("[QUERY]", exprPosition, count=count, comment=comment, prefix=prefix, suffix=suffix) unionVector = (exprPosition, count, comment, prefix, suffix)
if where == 1: if where == 1:
# Prepare expression with delimiters # Prepare expression with delimiters
@ -80,21 +76,20 @@ def __unionConfirm(comment, place, parameter, value, prefix, suffix, dbms, count
# 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
if not isinstance(kb.unionPosition, int): validPayload, unionVector = __unionPosition(comment, place, parameter, value, prefix, suffix, dbms, count)
validPayload, unionVector = __unionPosition(comment, place, parameter, value, prefix, suffix, dbms, 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 isinstance(kb.unionPosition, int): if not validPayload:
validPayload, unionVector = __unionPosition(comment, place, parameter, value, prefix, suffix, dbms, count, where=2) validPayload, unionVector = __unionPosition(comment, place, parameter, value, prefix, suffix, dbms, count, where=2)
# Assure that the above function found the exploitable partial # Assure that the above function found the exploitable partial
# (single entry) inband SQL injection position with negative # (single entry) inband SQL injection position with negative
# parameter validPayload # parameter validPayload
if not isinstance(kb.unionPosition, int): if not validPayload:
return None, None return None, None
else: else:
setUnion(negative=True) setUnion(negative=True)
return validPayload, unionVector return validPayload, unionVector
@ -126,7 +121,6 @@ def __unionTestByCharBruteforce(comment, place, parameter, value, prefix, suffix
validPayload, unionVector = __unionConfirm(comment, place, parameter, value, prefix, suffix, dbms, count) validPayload, unionVector = __unionConfirm(comment, place, parameter, value, prefix, suffix, dbms, count)
if validPayload: if validPayload:
setUnion(count=count)
break break
clearConsoleLine(True) clearConsoleLine(True)
@ -148,8 +142,5 @@ def unionTest(comment, place, parameter, value, prefix, suffix, dbms):
if validPayload: if validPayload:
validPayload = agent.removePayloadDelimiters(validPayload, False) validPayload = agent.removePayloadDelimiters(validPayload, False)
setUnion(char=conf.uChar)
setUnion(comment=comment)
setUnion(payload=validPayload)
return validPayload, unionVector return validPayload, unionVector

View File

@ -51,9 +51,6 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False, nullCh
if resetCounter: if resetCounter:
reqCount = 0 reqCount = 0
if not kb.unionCount:
return
# Prepare expression with delimiters # Prepare expression with delimiters
if unescape: if unescape:
expression = agent.concatQuery(expression, unpack) expression = agent.concatQuery(expression, unpack)
@ -211,8 +208,8 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False, nullCh
else: else:
# Forge the inband SQL injection request # Forge the inband SQL injection request
query = unescaper.unescape(expression) vector = kb.injection.data[PAYLOAD.TECHNIQUE.UNION].vector
query = agent.cleanupPayload(kb.injection.data[PAYLOAD.TECHNIQUE.UNION].vector, query=query) query = agent.forgeInbandQuery(expression, exprPosition=vector[0], count=vector[1], comment=vector[2], prefix=vector[3], suffix=vector[4])
payload = agent.payload(newValue=query) payload = agent.payload(newValue=query)
# Perform the request # 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 arrayizeValue
from lib.core.common import getRange from lib.core.common import getRange
from lib.core.common import isNumPosStrValue from lib.core.common import isNumPosStrValue
from lib.core.common import isTechniqueAvailable
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
@ -52,7 +53,7 @@ class Enumeration(GenericEnumeration):
else: else:
dbs = [conf.db] dbs = [conf.db]
if kb.unionPosition is not None or conf.direct: if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct:
for db in dbs: for db in dbs:
if conf.excludeSysDbs and db in self.excludeDbsList: if conf.excludeSysDbs and db in self.excludeDbsList:
infoMsg = "skipping system database '%s'" % db infoMsg = "skipping system database '%s'" % db
@ -142,7 +143,7 @@ class Enumeration(GenericEnumeration):
continue continue
if kb.unionPosition is not None or conf.direct: if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct:
query = rootQuery.inband.query % db query = rootQuery.inband.query % db
query += tblQuery query += tblQuery
values = inject.getValue(query, blind=False, error=False) values = inject.getValue(query, blind=False, error=False)
@ -227,7 +228,7 @@ class Enumeration(GenericEnumeration):
continue 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 = rootQuery.inband.query % (db, db, db, db, db)
query += " AND %s" % colQuery.replace("[DB]", db) query += " AND %s" % colQuery.replace("[DB]", db)
values = inject.getValue(query, blind=False, error=False) 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 getRange
from lib.core.common import isNumPosStrValue from lib.core.common import isNumPosStrValue
from lib.core.common import isTechniqueAvailable
from lib.core.common import posixToNtSlashes from lib.core.common import posixToNtSlashes
from lib.core.common import randomStr from lib.core.common import randomStr
from lib.core.data import conf from lib.core.data import conf
@ -91,7 +92,7 @@ class Filesystem(GenericFilesystem):
binToHexQuery = binToHexQuery.replace(" ", "").replace("\n", " ") binToHexQuery = binToHexQuery.replace(" ", "").replace("\n", " ")
inject.goStacked(binToHexQuery) 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) 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: 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.agent import agent
from lib.core.common import getRange from lib.core.common import getRange
from lib.core.common import isNumPosStrValue from lib.core.common import isNumPosStrValue
from lib.core.common import isTechniqueAvailable
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
@ -39,7 +40,7 @@ class Enumeration(GenericEnumeration):
# Set containing the list of DBMS administrators # Set containing the list of DBMS administrators
areAdmins = set() areAdmins = set()
if kb.unionPosition is not None or conf.direct: if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct:
if query2: if query2:
query = rootQuery.inband.query2 query = rootQuery.inband.query2
condition = rootQuery.inband.condition2 condition = rootQuery.inband.condition2
@ -199,7 +200,7 @@ class Enumeration(GenericEnumeration):
colQuery = colQuery % column colQuery = colQuery % column
for db in dbs.keys(): 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 = rootQuery.inband.query
query += colQuery query += colQuery
values = inject.getValue(query, blind=False, error=False) 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.MSSQL and kb.dbmsVersion[0] in ( "2005", "2008" ) )
condition |= ( kb.dbms == DBMS.MYSQL and not kb.data.has_information_schema ) 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: if condition:
query = rootQuery.inband.query2 query = rootQuery.inband.query2
else: else:
@ -210,7 +210,7 @@ class Enumeration:
logger.info(infoMsg) 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" ): if kb.dbms == DBMS.MSSQL and kb.dbmsVersion[0] in ( "2005", "2008" ):
query = rootQuery.inband.query2 query = rootQuery.inband.query2
else: else:
@ -431,7 +431,7 @@ class Enumeration:
"E": "EXECUTE" "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: if kb.dbms == DBMS.MYSQL and not kb.data.has_information_schema:
query = rootQuery.inband.query2 query = rootQuery.inband.query2
condition = rootQuery.inband.condition2 condition = rootQuery.inband.condition2
@ -677,7 +677,7 @@ class Enumeration:
rootQuery = queries[kb.dbms].dbs 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: if kb.dbms == DBMS.MYSQL and not kb.data.has_information_schema:
query = rootQuery.inband.query2 query = rootQuery.inband.query2
else: else:
@ -784,7 +784,7 @@ class Enumeration:
else: else:
dbs = kb.data.cachedDbs 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 query = rootQuery.inband.query
condition = rootQuery.inband.condition if 'condition' in rootQuery.inband else None condition = rootQuery.inband.condition if 'condition' in rootQuery.inband else None
@ -977,7 +977,7 @@ class Enumeration:
infoMsg += "on database '%s'" % conf.db infoMsg += "on database '%s'" % conf.db
logger.info(infoMsg) 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 ): if kb.dbms in ( DBMS.MYSQL, DBMS.PGSQL ):
query = rootQuery.inband.query % (conf.tbl, conf.db) query = rootQuery.inband.query % (conf.tbl, conf.db)
query += condQuery query += condQuery
@ -1174,7 +1174,7 @@ class Enumeration:
entriesCount = 0 entriesCount = 0
if kb.unionPosition is not None or conf.direct: if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct:
if kb.dbms == DBMS.ORACLE: if kb.dbms == DBMS.ORACLE:
query = rootQuery.inband.query % (colString, conf.tbl.upper()) query = rootQuery.inband.query % (colString, conf.tbl.upper())
elif kb.dbms == DBMS.SQLITE: elif kb.dbms == DBMS.SQLITE:
@ -1516,7 +1516,7 @@ class Enumeration:
dbQuery = "%s%s" % (dbCond, dbCondParam) dbQuery = "%s%s" % (dbCond, dbCondParam)
dbQuery = dbQuery % db 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: if kb.dbms == DBMS.MYSQL and not kb.data.has_information_schema:
query = rootQuery.inband.query2 query = rootQuery.inband.query2
else: else:
@ -1624,7 +1624,7 @@ class Enumeration:
tblQuery = "%s%s" % (tblCond, tblCondParam) tblQuery = "%s%s" % (tblCond, tblCondParam)
tblQuery = tblQuery % tbl 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 = rootQuery.inband.query
query += tblQuery query += tblQuery
query += exclDbsQuery query += exclDbsQuery
@ -1774,7 +1774,7 @@ class Enumeration:
colQuery = "%s%s" % (colCond, colCondParam) colQuery = "%s%s" % (colCond, colCondParam)
colQuery = colQuery % column 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 = rootQuery.inband.query
query += colQuery query += colQuery
query += exclDbsQuery query += exclDbsQuery