mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2025-12-24 08:29:07 +00:00
Adding extra validation step in case of boolean-based blind (e.g. if unexpected 500 occurs)
This commit is contained in:
@@ -157,7 +157,7 @@ def checkSqlInjection(place, parameter, value):
|
||||
kb.testType = stype = test.stype
|
||||
clause = test.clause
|
||||
unionExtended = False
|
||||
trueCode = None
|
||||
trueCode, falseCode = None, None
|
||||
|
||||
if stype == PAYLOAD.TECHNIQUE.UNION:
|
||||
configUnion(test.request.char)
|
||||
@@ -561,7 +561,7 @@ def checkSqlInjection(place, parameter, value):
|
||||
trueCode = threadData.lastCode
|
||||
|
||||
if trueResult:
|
||||
# Just extra validation step (e.g. to check for dropping protection mechanisms)
|
||||
# Extra validation step (e.g. to check for DROP protection mechanisms)
|
||||
if SLEEP_TIME_MARKER in reqPayload:
|
||||
falseResult = Request.queryPage(reqPayload.replace(SLEEP_TIME_MARKER, "0"), place, timeBasedCompare=True, raise404=False)
|
||||
if falseResult:
|
||||
@@ -678,6 +678,7 @@ def checkSqlInjection(place, parameter, value):
|
||||
injection.data[stype].templatePayload = templatePayload
|
||||
injection.data[stype].matchRatio = kb.matchRatio
|
||||
injection.data[stype].trueCode = trueCode
|
||||
injection.data[stype].falseCode = falseCode
|
||||
|
||||
injection.conf.textOnly = conf.textOnly
|
||||
injection.conf.titles = conf.titles
|
||||
|
||||
@@ -1983,7 +1983,6 @@ def _setKnowledgeBaseAttributes(flushAll=True):
|
||||
kb.threadContinue = True
|
||||
kb.threadException = False
|
||||
kb.tableExistsChoice = None
|
||||
kb.timeValidCharsRun = 0
|
||||
kb.uChar = NULL
|
||||
kb.unionDuplicates = False
|
||||
kb.xpCmdshellAvailable = False
|
||||
|
||||
@@ -19,7 +19,7 @@ from lib.core.enums import OS
|
||||
from lib.core.revision import getRevisionNumber
|
||||
|
||||
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
|
||||
VERSION = "1.0.9.37"
|
||||
VERSION = "1.0.9.38"
|
||||
REVISION = getRevisionNumber()
|
||||
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
|
||||
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34}
|
||||
@@ -510,8 +510,8 @@ PARSE_HEADERS_LIMIT = 3
|
||||
# Step used in ORDER BY technique used for finding the right number of columns in UNION query injections
|
||||
ORDER_BY_STEP = 10
|
||||
|
||||
# Maximum number of times for revalidation of a character in time-based injections
|
||||
MAX_TIME_REVALIDATION_STEPS = 5
|
||||
# Maximum number of times for revalidation of a character in inference (as required)
|
||||
MAX_REVALIDATION_STEPS = 5
|
||||
|
||||
# Characters that can be used to split parameter values in provided command line (e.g. in --tamper)
|
||||
PARAMETER_SPLITTING_REGEX = r'[,|;]'
|
||||
@@ -547,7 +547,7 @@ HASHDB_FLUSH_RETRIES = 3
|
||||
HASHDB_END_TRANSACTION_RETRIES = 3
|
||||
|
||||
# Unique milestone value used for forced deprecation of old HashDB values (e.g. when changing hash/pickle mechanism)
|
||||
HASHDB_MILESTONE_VALUE = "QWdDkLzhxH" # python -c 'import random, string; print "".join(random.sample(string.ascii_letters, 10))'
|
||||
HASHDB_MILESTONE_VALUE = "BkfRWrtCYK" # python -c 'import random, string; print "".join(random.sample(string.ascii_letters, 10))'
|
||||
|
||||
# Warn user of possible delay due to large page dump in full UNION query injections
|
||||
LARGE_OUTPUT_THRESHOLD = 1024 ** 2
|
||||
|
||||
@@ -41,7 +41,7 @@ from lib.core.settings import INFERENCE_GREATER_CHAR
|
||||
from lib.core.settings import INFERENCE_EQUALS_CHAR
|
||||
from lib.core.settings import INFERENCE_NOT_EQUALS_CHAR
|
||||
from lib.core.settings import MAX_BISECTION_LENGTH
|
||||
from lib.core.settings import MAX_TIME_REVALIDATION_STEPS
|
||||
from lib.core.settings import MAX_REVALIDATION_STEPS
|
||||
from lib.core.settings import NULL
|
||||
from lib.core.settings import PARTIAL_HEX_VALUE_MARKER
|
||||
from lib.core.settings import PARTIAL_VALUE_MARKER
|
||||
@@ -198,8 +198,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
||||
|
||||
def validateChar(idx, value):
|
||||
"""
|
||||
Used in time-based inference (in case that original and retrieved
|
||||
value are not equal there will be a deliberate delay).
|
||||
Used in inference - in time-based SQLi if original and retrieved value are not equal there will be a deliberate delay
|
||||
"""
|
||||
|
||||
if "'%s'" % CHAR_INFERENCE_MARK not in payload:
|
||||
@@ -264,6 +263,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
||||
minChar = minValue = charTbl[0]
|
||||
firstCheck = False
|
||||
lastCheck = False
|
||||
unexpectedCode = False
|
||||
|
||||
while len(charTbl) != 1:
|
||||
position = None
|
||||
@@ -321,6 +321,12 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
||||
result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False)
|
||||
incrementCounter(kb.technique)
|
||||
|
||||
if not timeBasedCompare:
|
||||
unexpectedCode |= threadData.lastCode not in (kb.injection.data[kb.technique].falseCode, kb.injection.data[kb.technique].trueCode)
|
||||
if unexpectedCode:
|
||||
warnMsg = "unexpected HTTP code '%d' detected. Will use (extra) validation step in similar cases" % threadData.lastCode
|
||||
singleTimeWarnMessage(warnMsg)
|
||||
|
||||
if result:
|
||||
minValue = posValue
|
||||
|
||||
@@ -360,24 +366,25 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
||||
retVal = minValue + 1
|
||||
|
||||
if retVal in originalTbl or (retVal == ord('\n') and CHAR_INFERENCE_MARK in payload):
|
||||
if timeBasedCompare and not validateChar(idx, retVal):
|
||||
if (timeBasedCompare or unexpectedCode) and not validateChar(idx, retVal):
|
||||
if not kb.originalTimeDelay:
|
||||
kb.originalTimeDelay = conf.timeSec
|
||||
|
||||
kb.timeValidCharsRun = 0
|
||||
if retried < MAX_TIME_REVALIDATION_STEPS:
|
||||
threadData.validationRun = 0
|
||||
if retried < MAX_REVALIDATION_STEPS:
|
||||
errMsg = "invalid character detected. retrying.."
|
||||
logger.error(errMsg)
|
||||
|
||||
if kb.adjustTimeDelay is not ADJUST_TIME_DELAY.DISABLE:
|
||||
conf.timeSec += 1
|
||||
warnMsg = "increasing time delay to %d second%s " % (conf.timeSec, 's' if conf.timeSec > 1 else '')
|
||||
logger.warn(warnMsg)
|
||||
if timeBasedCompare:
|
||||
if kb.adjustTimeDelay is not ADJUST_TIME_DELAY.DISABLE:
|
||||
conf.timeSec += 1
|
||||
warnMsg = "increasing time delay to %d second%s " % (conf.timeSec, 's' if conf.timeSec > 1 else '')
|
||||
logger.warn(warnMsg)
|
||||
|
||||
if kb.adjustTimeDelay is ADJUST_TIME_DELAY.YES:
|
||||
dbgMsg = "turning off time auto-adjustment mechanism"
|
||||
logger.debug(dbgMsg)
|
||||
kb.adjustTimeDelay = ADJUST_TIME_DELAY.NO
|
||||
if kb.adjustTimeDelay is ADJUST_TIME_DELAY.YES:
|
||||
dbgMsg = "turning off time auto-adjustment mechanism"
|
||||
logger.debug(dbgMsg)
|
||||
kb.adjustTimeDelay = ADJUST_TIME_DELAY.NO
|
||||
|
||||
return getChar(idx, originalTbl, continuousOrder, expand, shiftTable, (retried or 0) + 1)
|
||||
else:
|
||||
@@ -387,8 +394,8 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
||||
return decodeIntToUnicode(retVal)
|
||||
else:
|
||||
if timeBasedCompare:
|
||||
kb.timeValidCharsRun += 1
|
||||
if kb.adjustTimeDelay is ADJUST_TIME_DELAY.NO and kb.timeValidCharsRun > VALID_TIME_CHARS_RUN_THRESHOLD:
|
||||
threadData.validationRun += 1
|
||||
if kb.adjustTimeDelay is ADJUST_TIME_DELAY.NO and threadData.validationRun > VALID_TIME_CHARS_RUN_THRESHOLD:
|
||||
dbgMsg = "turning back on time auto-adjustment mechanism"
|
||||
logger.debug(dbgMsg)
|
||||
kb.adjustTimeDelay = ADJUST_TIME_DELAY.YES
|
||||
|
||||
Reference in New Issue
Block a user