mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2026-10-12 02:22:55 +00:00
Making boolean inference some more robust against jitter
This commit is contained in:
@@ -818,6 +818,12 @@ def checkSqlInjection(place, parameter, value):
|
||||
injection.data[stype].trueCode = trueCode
|
||||
injection.data[stype].falseCode = falseCode
|
||||
|
||||
# reference bodies for inference.py's "resembles neither TRUE nor FALSE model"
|
||||
# anomaly guard (runtime-only; lets a transient same-HTTP-code junk response
|
||||
# trigger a validateChar re-check during boolean extraction)
|
||||
if method == PAYLOAD.METHOD.COMPARISON:
|
||||
kb.trueTemplate, kb.falseTemplate = truePage, falsePage
|
||||
|
||||
injection.conf.textOnly = conf.textOnly
|
||||
injection.conf.titles = conf.titles
|
||||
injection.conf.code = conf.code
|
||||
|
||||
@@ -2305,6 +2305,10 @@ def _setKnowledgeBaseAttributes(flushAll=True):
|
||||
kb.pageTemplate = None
|
||||
kb.pageTemplates = dict()
|
||||
kb.pageEncoding = DEFAULT_PAGE_ENCODING
|
||||
|
||||
# calibrated TRUE/FALSE reference bodies for the boolean same-HTTP-code anomaly guard (inference.py)
|
||||
kb.trueTemplate = None
|
||||
kb.falseTemplate = None
|
||||
kb.pageStable = None
|
||||
kb.pageStructurallyStable = None
|
||||
kb.partRun = None
|
||||
|
||||
@@ -20,7 +20,7 @@ from lib.core.enums import OS
|
||||
from thirdparty import six
|
||||
|
||||
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
|
||||
VERSION = "1.10.7.241"
|
||||
VERSION = "1.10.7.242"
|
||||
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
|
||||
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34}
|
||||
VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE)
|
||||
@@ -103,6 +103,11 @@ LIVE_COOKIES_TIMEOUT = 120
|
||||
LOWER_RATIO_BOUND = 0.02
|
||||
UPPER_RATIO_BOUND = 0.98
|
||||
|
||||
# Minimum similarity at which a boolean extraction response is judged to "resemble" the calibrated
|
||||
# TRUE or FALSE model. A response resembling NEITHER (a transient same-HTTP-code junk page: WAF/CDN
|
||||
# interstitial, captcha, maintenance, empty/truncated body) triggers an extra validateChar re-check.
|
||||
BOOLEAN_MODEL_MATCH_RATIO = 0.9
|
||||
|
||||
# Number of candidate names probed per request while mining for hidden parameters ('--mine-params')
|
||||
PARAMETER_MINING_BUCKET_SIZE = 25
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ See the file 'LICENSE' for copying permission
|
||||
|
||||
from __future__ import division
|
||||
|
||||
import difflib
|
||||
import heapq
|
||||
import re
|
||||
import time
|
||||
@@ -26,6 +27,7 @@ from lib.core.common import getTechnique
|
||||
from lib.core.common import getTechniqueData
|
||||
from lib.core.common import getText
|
||||
from lib.core.common import predictValue
|
||||
from lib.core.common import removeDynamicContent
|
||||
from lib.core.common import hashDBRetrieve
|
||||
from lib.core.common import hashDBWrite
|
||||
from lib.core.common import incrementCounter
|
||||
@@ -45,6 +47,7 @@ from lib.core.enums import PAYLOAD
|
||||
from lib.core.exception import SqlmapThreadException
|
||||
from lib.core.exception import SqlmapUnsupportedFeatureException
|
||||
from lib.core.wordlist import Wordlist
|
||||
from lib.core.settings import BOOLEAN_MODEL_MATCH_RATIO
|
||||
from lib.core.settings import CHAR_INFERENCE_MARK
|
||||
from lib.core.settings import HUFFMAN_PROBE_LIMIT
|
||||
from lib.core.settings import HUFFMAN_PRIOR_WEIGHTS
|
||||
@@ -256,6 +259,31 @@ def oracleReliabilityLitmus(expressionUnescaped, value, timeBasedCompare):
|
||||
|
||||
return bool(mustBeTrue) and not bool(mustBeFalse)
|
||||
|
||||
def _resemblesNeitherModel(page):
|
||||
"""
|
||||
Returns True when a boolean extraction response resembles NEITHER the calibrated TRUE nor FALSE
|
||||
model (kb.trueTemplate / kb.falseTemplate). A transient response that keeps the expected HTTP code
|
||||
but swaps the body for junk (WAF/CDN interstitial, captcha, maintenance banner, empty/truncated
|
||||
page) is invisible to the HTTP-code check, so it is flagged here for an extra validateChar re-check.
|
||||
|
||||
This only ever ADDS a re-validation - it never changes a decided bit - so it is a safe no-op on a
|
||||
clean target (every response resembles its own model) and when no models were recorded (a resumed
|
||||
session, or a non-boolean technique).
|
||||
"""
|
||||
|
||||
refs = [_ for _ in (kb.trueTemplate, kb.falseTemplate) if _]
|
||||
if not refs:
|
||||
return False
|
||||
if page is None:
|
||||
return True
|
||||
|
||||
cleaned = removeDynamicContent(page)
|
||||
for ref in refs:
|
||||
if difflib.SequenceMatcher(None, removeDynamicContent(ref), cleaned).quick_ratio() >= BOOLEAN_MODEL_MATCH_RATIO:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def bisection(payload, expression, length=None, charsetType=None, firstChar=None, lastChar=None, dump=False):
|
||||
"""
|
||||
Bisection algorithm that can be used to perform blind SQL injection
|
||||
@@ -714,6 +742,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
||||
firstCheck = False
|
||||
lastCheck = False
|
||||
unexpectedCode = False
|
||||
unexpectedResponse = False
|
||||
|
||||
if continuousOrder:
|
||||
while len(charTbl) > 1:
|
||||
@@ -787,6 +816,13 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
||||
|
||||
singleTimeWarnMessage(warnMsg)
|
||||
|
||||
# same-HTTP-code body anomaly (WAF/CDN interstitial, captcha, maintenance, empty
|
||||
# or truncated body) - invisible to the code check above, so re-validate when the
|
||||
# response resembles neither calibrated model
|
||||
elif not unexpectedResponse and not kb.nullConnection and _resemblesNeitherModel(threadData.lastPage):
|
||||
unexpectedResponse = True
|
||||
singleTimeWarnMessage("unexpected response content detected. Will use (extra) validation step in similar cases")
|
||||
|
||||
if result:
|
||||
minValue = posValue
|
||||
|
||||
@@ -826,7 +862,7 @@ 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 or unexpectedCode) and kb.get("timeless") is None and not validateChar(idx, retVal):
|
||||
if (timeBasedCompare or unexpectedCode or unexpectedResponse) and kb.get("timeless") is None and not validateChar(idx, retVal):
|
||||
if restricted:
|
||||
# the character fell outside this column's observed range - re-extract
|
||||
# over the full charset (not timing noise, so no delay increase / retry count)
|
||||
|
||||
Reference in New Issue
Block a user