mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2025-01-24 00:04:23 +03:00
Fixes #1305
This commit is contained in:
parent
a7c4400cc9
commit
21e8182ac6
|
@ -1249,10 +1249,10 @@ def checkNullConnection():
|
||||||
infoMsg = "testing NULL connection to the target URL"
|
infoMsg = "testing NULL connection to the target URL"
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
pushValue(kb.pageCompress)
|
|
||||||
kb.pageCompress = False
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
pushValue(kb.pageCompress)
|
||||||
|
kb.pageCompress = False
|
||||||
|
|
||||||
page, headers, _ = Request.getPage(method=HTTPMETHOD.HEAD)
|
page, headers, _ = Request.getPage(method=HTTPMETHOD.HEAD)
|
||||||
|
|
||||||
if not page and HTTP_HEADER.CONTENT_LENGTH in (headers or {}):
|
if not page and HTTP_HEADER.CONTENT_LENGTH in (headers or {}):
|
||||||
|
@ -1282,7 +1282,8 @@ def checkNullConnection():
|
||||||
errMsg = getUnicode(errMsg)
|
errMsg = getUnicode(errMsg)
|
||||||
raise SqlmapConnectionException(errMsg)
|
raise SqlmapConnectionException(errMsg)
|
||||||
|
|
||||||
kb.pageCompress = popValue()
|
finally:
|
||||||
|
kb.pageCompress = popValue()
|
||||||
|
|
||||||
return kb.nullConnection is not None
|
return kb.nullConnection is not None
|
||||||
|
|
||||||
|
|
|
@ -501,47 +501,49 @@ def start():
|
||||||
kb.testedParams.add(paramKey)
|
kb.testedParams.add(paramKey)
|
||||||
|
|
||||||
if testSqlInj:
|
if testSqlInj:
|
||||||
if place == PLACE.COOKIE:
|
try:
|
||||||
pushValue(kb.mergeCookies)
|
if place == PLACE.COOKIE:
|
||||||
kb.mergeCookies = False
|
pushValue(kb.mergeCookies)
|
||||||
|
kb.mergeCookies = False
|
||||||
|
|
||||||
check = heuristicCheckSqlInjection(place, parameter)
|
check = heuristicCheckSqlInjection(place, parameter)
|
||||||
|
|
||||||
if check != HEURISTIC_TEST.POSITIVE:
|
if check != HEURISTIC_TEST.POSITIVE:
|
||||||
if conf.smart or (kb.ignoreCasted and check == HEURISTIC_TEST.CASTED):
|
if conf.smart or (kb.ignoreCasted and check == HEURISTIC_TEST.CASTED):
|
||||||
infoMsg = "skipping %s parameter '%s'" % (paramType, parameter)
|
infoMsg = "skipping %s parameter '%s'" % (paramType, parameter)
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
infoMsg = "testing for SQL injection on %s " % paramType
|
infoMsg = "testing for SQL injection on %s " % paramType
|
||||||
infoMsg += "parameter '%s'" % parameter
|
infoMsg += "parameter '%s'" % parameter
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
injection = checkSqlInjection(place, parameter, value)
|
injection = checkSqlInjection(place, parameter, value)
|
||||||
proceed = not kb.endDetection
|
proceed = not kb.endDetection
|
||||||
|
|
||||||
if injection is not None and injection.place is not None:
|
if injection is not None and injection.place is not None:
|
||||||
kb.injections.append(injection)
|
kb.injections.append(injection)
|
||||||
|
|
||||||
# In case when user wants to end detection phase (Ctrl+C)
|
# In case when user wants to end detection phase (Ctrl+C)
|
||||||
if not proceed:
|
if not proceed:
|
||||||
break
|
break
|
||||||
|
|
||||||
msg = "%s parameter '%s' " % (injection.place, injection.parameter)
|
msg = "%s parameter '%s' " % (injection.place, injection.parameter)
|
||||||
msg += "is vulnerable. Do you want to keep testing the others (if any)? [y/N] "
|
msg += "is vulnerable. Do you want to keep testing the others (if any)? [y/N] "
|
||||||
test = readInput(msg, default="N")
|
test = readInput(msg, default="N")
|
||||||
|
|
||||||
if test[0] not in ("y", "Y"):
|
if test[0] not in ("y", "Y"):
|
||||||
proceed = False
|
proceed = False
|
||||||
paramKey = (conf.hostname, conf.path, None, None)
|
paramKey = (conf.hostname, conf.path, None, None)
|
||||||
kb.testedParams.add(paramKey)
|
kb.testedParams.add(paramKey)
|
||||||
else:
|
else:
|
||||||
warnMsg = "%s parameter '%s' is not " % (paramType, parameter)
|
warnMsg = "%s parameter '%s' is not " % (paramType, parameter)
|
||||||
warnMsg += "injectable"
|
warnMsg += "injectable"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
if place == PLACE.COOKIE:
|
finally:
|
||||||
kb.mergeCookies = popValue()
|
if place == PLACE.COOKIE:
|
||||||
|
kb.mergeCookies = popValue()
|
||||||
|
|
||||||
if len(kb.injections) == 0 or (len(kb.injections) == 1 and kb.injections[0].place is None):
|
if len(kb.injections) == 0 or (len(kb.injections) == 1 and kb.injections[0].place is None):
|
||||||
if kb.vainRun and not conf.multipleTargets:
|
if kb.vainRun and not conf.multipleTargets:
|
||||||
|
|
|
@ -1030,23 +1030,24 @@ class Connect(object):
|
||||||
if kb.nullConnection and not content and not response and not timeBasedCompare:
|
if kb.nullConnection and not content and not response and not timeBasedCompare:
|
||||||
noteResponseTime = False
|
noteResponseTime = False
|
||||||
|
|
||||||
pushValue(kb.pageCompress)
|
try:
|
||||||
kb.pageCompress = False
|
pushValue(kb.pageCompress)
|
||||||
|
kb.pageCompress = False
|
||||||
|
|
||||||
if kb.nullConnection == NULLCONNECTION.HEAD:
|
if kb.nullConnection == NULLCONNECTION.HEAD:
|
||||||
method = HTTPMETHOD.HEAD
|
method = HTTPMETHOD.HEAD
|
||||||
elif kb.nullConnection == NULLCONNECTION.RANGE:
|
elif kb.nullConnection == NULLCONNECTION.RANGE:
|
||||||
auxHeaders[HTTP_HEADER.RANGE] = "bytes=-1"
|
auxHeaders[HTTP_HEADER.RANGE] = "bytes=-1"
|
||||||
|
|
||||||
_, headers, code = Connect.getPage(url=uri, get=get, post=post, method=method, cookie=cookie, ua=ua, referer=referer, host=host, silent=silent, auxHeaders=auxHeaders, raise404=raise404, skipRead=(kb.nullConnection == NULLCONNECTION.SKIP_READ))
|
_, headers, code = Connect.getPage(url=uri, get=get, post=post, method=method, cookie=cookie, ua=ua, referer=referer, host=host, silent=silent, auxHeaders=auxHeaders, raise404=raise404, skipRead=(kb.nullConnection == NULLCONNECTION.SKIP_READ))
|
||||||
|
|
||||||
if headers:
|
if headers:
|
||||||
if kb.nullConnection in (NULLCONNECTION.HEAD, NULLCONNECTION.SKIP_READ) and HTTP_HEADER.CONTENT_LENGTH in headers:
|
if kb.nullConnection in (NULLCONNECTION.HEAD, NULLCONNECTION.SKIP_READ) and HTTP_HEADER.CONTENT_LENGTH in headers:
|
||||||
pageLength = int(headers[HTTP_HEADER.CONTENT_LENGTH])
|
pageLength = int(headers[HTTP_HEADER.CONTENT_LENGTH])
|
||||||
elif kb.nullConnection == NULLCONNECTION.RANGE and HTTP_HEADER.CONTENT_RANGE in headers:
|
elif kb.nullConnection == NULLCONNECTION.RANGE and HTTP_HEADER.CONTENT_RANGE in headers:
|
||||||
pageLength = int(headers[HTTP_HEADER.CONTENT_RANGE][headers[HTTP_HEADER.CONTENT_RANGE].find('/') + 1:])
|
pageLength = int(headers[HTTP_HEADER.CONTENT_RANGE][headers[HTTP_HEADER.CONTENT_RANGE].find('/') + 1:])
|
||||||
|
finally:
|
||||||
kb.pageCompress = popValue()
|
kb.pageCompress = popValue()
|
||||||
|
|
||||||
if not pageLength:
|
if not pageLength:
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -391,11 +391,13 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser
|
||||||
warnMsg += ". Falling back to partial UNION technique"
|
warnMsg += ". Falling back to partial UNION technique"
|
||||||
singleTimeWarnMessage(warnMsg)
|
singleTimeWarnMessage(warnMsg)
|
||||||
|
|
||||||
pushValue(kb.forcePartialUnion)
|
try:
|
||||||
kb.forcePartialUnion = True
|
pushValue(kb.forcePartialUnion)
|
||||||
value = _goUnion(query, unpack, dump)
|
kb.forcePartialUnion = True
|
||||||
found = (value is not None) or (value is None and expectingNone)
|
value = _goUnion(query, unpack, dump)
|
||||||
kb.forcePartialUnion = popValue()
|
found = (value is not None) or (value is None and expectingNone)
|
||||||
|
finally:
|
||||||
|
kb.forcePartialUnion = popValue()
|
||||||
else:
|
else:
|
||||||
singleTimeWarnMessage(warnMsg)
|
singleTimeWarnMessage(warnMsg)
|
||||||
|
|
||||||
|
|
|
@ -81,73 +81,74 @@ def _findUnionCharCount(comment, place, parameter, value, prefix, suffix, where=
|
||||||
|
|
||||||
return found
|
return found
|
||||||
|
|
||||||
pushValue(kb.errorIsNone)
|
try:
|
||||||
items, ratios = [], []
|
pushValue(kb.errorIsNone)
|
||||||
kb.errorIsNone = False
|
items, ratios = [], []
|
||||||
lowerCount, upperCount = conf.uColsStart, conf.uColsStop
|
kb.errorIsNone = False
|
||||||
|
lowerCount, upperCount = conf.uColsStart, conf.uColsStop
|
||||||
|
|
||||||
if lowerCount == 1:
|
if lowerCount == 1:
|
||||||
found = kb.orderByColumns or _orderByTechnique()
|
found = kb.orderByColumns or _orderByTechnique()
|
||||||
if found:
|
if found:
|
||||||
kb.orderByColumns = found
|
kb.orderByColumns = found
|
||||||
infoMsg = "target URL appears to have %d column%s in query" % (found, 's' if found > 1 else "")
|
infoMsg = "target URL appears to have %d column%s in query" % (found, 's' if found > 1 else "")
|
||||||
singleTimeLogMessage(infoMsg)
|
singleTimeLogMessage(infoMsg)
|
||||||
return found
|
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
|
||||||
|
|
||||||
min_, max_ = MAX_RATIO, MIN_RATIO
|
min_, max_ = MAX_RATIO, MIN_RATIO
|
||||||
pages = {}
|
pages = {}
|
||||||
|
|
||||||
|
for count in xrange(lowerCount, upperCount + 1):
|
||||||
|
query = agent.forgeUnionQuery('', -1, count, comment, prefix, suffix, kb.uChar, where)
|
||||||
|
payload = agent.payload(place=place, parameter=parameter, newValue=query, where=where)
|
||||||
|
page, headers = Request.queryPage(payload, place=place, content=True, raise404=False)
|
||||||
|
if not isNullValue(kb.uChar):
|
||||||
|
pages[count] = page
|
||||||
|
ratio = comparison(page, headers, getRatioValue=True) or MIN_RATIO
|
||||||
|
ratios.append(ratio)
|
||||||
|
min_, max_ = min(min_, ratio), max(max_, ratio)
|
||||||
|
items.append((count, ratio))
|
||||||
|
|
||||||
for count in xrange(lowerCount, upperCount + 1):
|
|
||||||
query = agent.forgeUnionQuery('', -1, count, comment, prefix, suffix, kb.uChar, where)
|
|
||||||
payload = agent.payload(place=place, parameter=parameter, newValue=query, where=where)
|
|
||||||
page, headers = Request.queryPage(payload, place=place, content=True, raise404=False)
|
|
||||||
if not isNullValue(kb.uChar):
|
if not isNullValue(kb.uChar):
|
||||||
pages[count] = page
|
for regex in (kb.uChar, r'>\s*%s\s*<' % kb.uChar):
|
||||||
ratio = comparison(page, headers, getRatioValue=True) or MIN_RATIO
|
contains = [(count, re.search(regex, page or "", re.IGNORECASE) is not None) for count, page in pages.items()]
|
||||||
ratios.append(ratio)
|
if len(filter(lambda x: x[1], contains)) == 1:
|
||||||
min_, max_ = min(min_, ratio), max(max_, ratio)
|
retVal = filter(lambda x: x[1], contains)[0][0]
|
||||||
items.append((count, ratio))
|
break
|
||||||
|
|
||||||
if not isNullValue(kb.uChar):
|
if not retVal:
|
||||||
for regex in (kb.uChar, r'>\s*%s\s*<' % kb.uChar):
|
ratios.pop(ratios.index(min_))
|
||||||
contains = [(count, re.search(regex, page or "", re.IGNORECASE) is not None) for count, page in pages.items()]
|
ratios.pop(ratios.index(max_))
|
||||||
if len(filter(lambda x: x[1], contains)) == 1:
|
|
||||||
retVal = filter(lambda x: x[1], contains)[0][0]
|
|
||||||
break
|
|
||||||
|
|
||||||
if not retVal:
|
minItem, maxItem = None, None
|
||||||
ratios.pop(ratios.index(min_))
|
|
||||||
ratios.pop(ratios.index(max_))
|
|
||||||
|
|
||||||
minItem, maxItem = None, None
|
for item in items:
|
||||||
|
if item[1] == min_:
|
||||||
|
minItem = item
|
||||||
|
elif item[1] == max_:
|
||||||
|
maxItem = item
|
||||||
|
|
||||||
for item in items:
|
if all(map(lambda x: x == min_ and x != max_, ratios)):
|
||||||
if item[1] == min_:
|
retVal = maxItem[0]
|
||||||
minItem = item
|
|
||||||
elif item[1] == max_:
|
|
||||||
maxItem = item
|
|
||||||
|
|
||||||
if all(map(lambda x: x == min_ and x != max_, ratios)):
|
elif all(map(lambda x: x != min_ and x == max_, ratios)):
|
||||||
retVal = maxItem[0]
|
retVal = minItem[0]
|
||||||
|
|
||||||
elif all(map(lambda x: x != min_ and x == max_, ratios)):
|
elif abs(max_ - min_) >= MIN_STATISTICAL_RANGE:
|
||||||
retVal = minItem[0]
|
deviation = stdev(ratios)
|
||||||
|
lower, upper = average(ratios) - UNION_STDEV_COEFF * deviation, average(ratios) + UNION_STDEV_COEFF * deviation
|
||||||
|
|
||||||
elif abs(max_ - min_) >= MIN_STATISTICAL_RANGE:
|
if min_ < lower:
|
||||||
deviation = stdev(ratios)
|
retVal = minItem[0]
|
||||||
lower, upper = average(ratios) - UNION_STDEV_COEFF * deviation, average(ratios) + UNION_STDEV_COEFF * deviation
|
|
||||||
|
|
||||||
if min_ < lower:
|
if max_ > upper:
|
||||||
retVal = minItem[0]
|
if retVal is None or abs(max_ - upper) > abs(min_ - lower):
|
||||||
|
retVal = maxItem[0]
|
||||||
if max_ > upper:
|
finally:
|
||||||
if retVal is None or abs(max_ - upper) > abs(min_ - lower):
|
kb.errorIsNone = popValue()
|
||||||
retVal = maxItem[0]
|
|
||||||
|
|
||||||
kb.errorIsNone = popValue()
|
|
||||||
|
|
||||||
if retVal:
|
if retVal:
|
||||||
infoMsg = "target URL appears to be UNION injectable with %d columns" % retVal
|
infoMsg = "target URL appears to be UNION injectable with %d columns" % retVal
|
||||||
|
|
|
@ -742,32 +742,33 @@ class Databases:
|
||||||
infoMsg = "enumerating database management system schema"
|
infoMsg = "enumerating database management system schema"
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
pushValue(conf.db)
|
try:
|
||||||
pushValue(conf.tbl)
|
pushValue(conf.db)
|
||||||
pushValue(conf.col)
|
pushValue(conf.tbl)
|
||||||
|
pushValue(conf.col)
|
||||||
|
|
||||||
kb.data.cachedTables = {}
|
kb.data.cachedTables = {}
|
||||||
kb.data.cachedColumns = {}
|
kb.data.cachedColumns = {}
|
||||||
|
|
||||||
self.getTables()
|
self.getTables()
|
||||||
|
|
||||||
infoMsg = "fetched tables: "
|
infoMsg = "fetched tables: "
|
||||||
infoMsg += ", ".join(["%s" % ", ".join("%s%s%s" % (unsafeSQLIdentificatorNaming(db), ".." if \
|
infoMsg += ", ".join(["%s" % ", ".join("%s%s%s" % (unsafeSQLIdentificatorNaming(db), ".." if \
|
||||||
Backend.isDbms(DBMS.MSSQL) or Backend.isDbms(DBMS.SYBASE) \
|
Backend.isDbms(DBMS.MSSQL) or Backend.isDbms(DBMS.SYBASE) \
|
||||||
else ".", unsafeSQLIdentificatorNaming(t)) for t in tbl) for db, tbl in \
|
else ".", unsafeSQLIdentificatorNaming(t)) for t in tbl) for db, tbl in \
|
||||||
kb.data.cachedTables.items()])
|
kb.data.cachedTables.items()])
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
for db, tables in kb.data.cachedTables.items():
|
for db, tables in kb.data.cachedTables.items():
|
||||||
for tbl in tables:
|
for tbl in tables:
|
||||||
conf.db = db
|
conf.db = db
|
||||||
conf.tbl = tbl
|
conf.tbl = tbl
|
||||||
|
|
||||||
self.getColumns()
|
self.getColumns()
|
||||||
|
finally:
|
||||||
conf.col = popValue()
|
conf.col = popValue()
|
||||||
conf.tbl = popValue()
|
conf.tbl = popValue()
|
||||||
conf.db = popValue()
|
conf.db = popValue()
|
||||||
|
|
||||||
return kb.data.cachedColumns
|
return kb.data.cachedColumns
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user