From 16cd9425ae75a307f1012260eaf55b3de86e162e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20=C5=A0tampar?= Date: Sun, 12 Jul 2026 14:42:34 +0200 Subject: [PATCH] Introducing detection switch --lengths --- lib/controller/checks.py | 15 +++++++++++---- lib/core/common.py | 1 + lib/core/option.py | 1 + lib/core/settings.py | 2 +- lib/parse/cmdline.py | 3 +++ lib/request/comparison.py | 4 ++++ 6 files changed, 21 insertions(+), 5 deletions(-) diff --git a/lib/controller/checks.py b/lib/controller/checks.py index d190d4782..527a52e3f 100644 --- a/lib/controller/checks.py +++ b/lib/controller/checks.py @@ -523,6 +523,7 @@ def checkSqlInjection(place, parameter, value): # Useful to set kb.matchRatio at first based on False response content kb.matchRatio = None + kb.trueLength = None kb.negativeLogic = (where == PAYLOAD.WHERE.NEGATIVE) suggestion = None Request.queryPage(genCmpPayload(), place, raise404=False) @@ -530,7 +531,7 @@ def checkSqlInjection(place, parameter, value): falseRawResponse = "%s%s" % (falseHeaders, falsePage) # Checking if there is difference between current FALSE, original and heuristics page (i.e. not used parameter) - if not any((kb.negativeLogic, conf.string, conf.notString, conf.code)): + if not any((kb.negativeLogic, conf.string, conf.notString, conf.code, conf.lengths)): try: ratio = 1.0 seqMatcher = getCurrentThreadData().seqMatcher @@ -550,6 +551,10 @@ def checkSqlInjection(place, parameter, value): truePage, trueHeaders, trueCode = threadData.lastComparisonPage or "", threadData.lastComparisonHeaders, threadData.lastComparisonCode trueRawResponse = "%s%s" % (trueHeaders, truePage) + if conf.lengths: + kb.trueLength = len(truePage) + trueResult = True + if trueResult and not (truePage == falsePage and not any((kb.nullConnection, conf.code))): # Perform the test's False request falseResult = Request.queryPage(genCmpPayload(), place, raise404=False) @@ -563,7 +568,7 @@ def checkSqlInjection(place, parameter, value): errorResult = Request.queryPage(errorPayload, place, raise404=False) if errorResult: continue - elif kb.heuristicPage and not any((conf.string, conf.notString, conf.regexp, conf.code, kb.nullConnection)): + elif kb.heuristicPage and not any((conf.string, conf.notString, conf.regexp, conf.code, conf.lengths, kb.nullConnection)): _ = comparison(kb.heuristicPage, None, getRatioValue=True) if (_ or 0) > (kb.matchRatio or 0): kb.matchRatio = _ @@ -575,7 +580,7 @@ def checkSqlInjection(place, parameter, value): injectable = True - elif (threadData.lastComparisonRatio or 0) > UPPER_RATIO_BOUND and not any((conf.string, conf.notString, conf.regexp, conf.code, conf.titles, kb.nullConnection)): + elif (threadData.lastComparisonRatio or 0) > UPPER_RATIO_BOUND and not any((conf.string, conf.notString, conf.regexp, conf.code, conf.lengths, conf.titles, kb.nullConnection)): originalSet = set(getFilteredPageContent(kb.pageTemplate, True, "\n").split("\n")) trueSet = set(getFilteredPageContent(truePage, True, "\n").split("\n")) falseSet = set(getFilteredPageContent(falsePage, True, "\n").split("\n")) @@ -613,7 +618,7 @@ def checkSqlInjection(place, parameter, value): injectable = False continue - if kb.pageStable and not any((conf.string, conf.notString, conf.regexp, conf.code, conf.titles, kb.nullConnection)): + if kb.pageStable and not any((conf.string, conf.notString, conf.regexp, conf.code, conf.lengths, conf.titles, kb.nullConnection)): if all((falseCode, trueCode)) and falseCode != trueCode and trueCode != kb.heuristicCode: suggestion = conf.code = trueCode @@ -805,12 +810,14 @@ def checkSqlInjection(place, parameter, value): injection.data[stype].comment = comment injection.data[stype].templatePayload = templatePayload injection.data[stype].matchRatio = kb.matchRatio + injection.data[stype].trueLength = kb.trueLength injection.data[stype].trueCode = trueCode injection.data[stype].falseCode = falseCode injection.conf.textOnly = conf.textOnly injection.conf.titles = conf.titles injection.conf.code = conf.code + injection.conf.lengths = conf.lengths injection.conf.string = conf.string injection.conf.notString = conf.notString injection.conf.regexp = conf.regexp diff --git a/lib/core/common.py b/lib/core/common.py index 66e4140ed..65d702c33 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -3746,6 +3746,7 @@ def initTechnique(technique=None): if data: kb.pageTemplate, kb.errorIsNone = getPageTemplate(data.templatePayload, kb.injection.place) kb.matchRatio = data.matchRatio + kb.trueLength = data.trueLength kb.negativeLogic = (technique == PAYLOAD.TECHNIQUE.BOOLEAN) and (data.where == PAYLOAD.WHERE.NEGATIVE) # Restoring stored conf options diff --git a/lib/core/option.py b/lib/core/option.py index d61134aa5..c808d2b7b 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -2264,6 +2264,7 @@ def _setKnowledgeBaseAttributes(flushAll=True): kb.matchRatio = None kb.maxConnectionsFlag = False + kb.trueLength = None kb.mergeCookies = None kb.multiThreadMode = False kb.multipleCtrlC = False diff --git a/lib/core/settings.py b/lib/core/settings.py index 42e82a9b5..ba4a2e6f5 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -20,7 +20,7 @@ from lib.core.enums import OS from thirdparty import six # sqlmap version (...) -VERSION = "1.10.7.92" +VERSION = "1.10.7.93" 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) diff --git a/lib/parse/cmdline.py b/lib/parse/cmdline.py index c1e0f9ed9..c30520f6a 100644 --- a/lib/parse/cmdline.py +++ b/lib/parse/cmdline.py @@ -406,6 +406,9 @@ def cmdLineParser(argv=None): detection.add_argument("--code", dest="code", type=int, help="HTTP code to match when query is evaluated to True") + detection.add_argument("--lengths", dest="lengths", action="store_true", + help="Compare pages based only on their content length") + detection.add_argument("--smart", dest="smart", action="store_true", help="Perform thorough tests only if positive heuristic(s)") diff --git a/lib/request/comparison.py b/lib/request/comparison.py index 30beafabc..891338353 100644 --- a/lib/request/comparison.py +++ b/lib/request/comparison.py @@ -114,6 +114,10 @@ def _comparison(page, headers, code, getRatioValue, pageLength): if conf.code: return conf.code == code + # Response content length to match when the query is True + if conf.lengths: + return len(page or "") == kb.trueLength + seqMatcher = threadData.seqMatcher seqMatcher.set_seq1(kb.pageTemplate)