Patching non-SQLi techniques regarding reflective values

This commit is contained in:
Miroslav Štampar
2026-08-08 00:55:37 +02:00
parent 61ffadb487
commit aa8d9b9841
5 changed files with 31 additions and 3 deletions
+12
View File
@@ -1194,6 +1194,18 @@ class ReqHandler(BaseHTTPRequestHandler):
self.wfile.write(output.encode(UNICODE_ENCODING))
return
if self.url == "/echo":
# A pure reflector: no engine of any kind behind it, it only shows the parameter back. Every
# non-SQL switch must stay silent here. A differential built on "the page changed" is
# satisfied by reflection alone, which is how several engines reported this shape as
# injectable - so this endpoint is the regression gate for that whole class.
self.send_response(OK)
self.send_header("Content-type", "text/html; charset=%s" % UNICODE_ENCODING)
self.send_header("Connection", "close")
self.end_headers()
self.wfile.write(("<html><body>you searched for: %s</body></html>" % self.params.get("q", "")).encode(UNICODE_ENCODING))
return
if self.url in ("/xslt/element", "/xslt/value"):
# VULNERABLE: user input is concatenated into a stylesheet which is then compiled and applied
element = self.url.endswith("element")
+1 -1
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.8.14"
VERSION = "1.10.8.15"
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)
+4
View File
@@ -96,6 +96,10 @@ def vulnTest(tests=None, label="vuln"):
("-u \"<base>nosql?name=luther&password=x\" -p password --nosql --flush-session", ("is vulnerable to NoSQL injection", "back-end: 'MongoDB'", "NoSQL: GET parameter 'password'", "s3cr3t")), # NoSQL (MongoDB) operator-injection detection + blind regexp extraction
("-u \"<base>graphql\" --graphql --flush-session --disable-hashing", ("found GraphQL endpoint", "introspection returned", "enumerated 6 injectable argument slot(s): 4 query, 2 mutation", "SQL injection via GraphQL (boolean-based)", "in-band data exposure", "back-end DBMS: 'SQLite'", "banner: '3.", "GraphQL database tables", "fetched 30 entries from table 'creds'", "db3a16990a0008a3b04707fdef6584a0", "GraphQL scan complete")), # GraphQL: endpoint detection + introspection + query-slots-first (mutations only as fallback) + boolean-blind/in-band + back-end fingerprint + batched blind dump of an injection-only table (SQLite-backed)
("-u \"<base>ldap/search?q=x\" --ldap --flush-session --disable-hashing", ("is vulnerable to LDAP injection", "Title: LDAP in-band data exposure", "LDAP: GET parameter 'q' in-band entries", "in-band data exposure", "LDAP scan complete")), # LDAP: error-based detection (unbalanced paren) + boolean oracle + directory attribute extraction via blind substring probing
("-u \"<base>echo?q=x\" --xslt --flush-session --disable-hashing", ("no parameter appears to be injectable", "~is vulnerable to")), # reflection is not evaluation: a pure echo endpoint must not satisfy any non-SQL engine's oracle
("-u \"<base>echo?q=x\" --xpath --flush-session --disable-hashing", ("no parameter appears to be injectable", "~is vulnerable to")), # same gate for --xpath (it used to confirm XPath injection from reflected text alone)
("-u \"<base>echo?q=x\" --ldap --flush-session --disable-hashing", ("no parameter appears to be injectable", "~is vulnerable to", "~Traceback")), # same gate for --ldap (it used to CRASH here with an unhandled InconclusiveError)
("-u \"<base>echo?q=x\" --nosql --flush-session --disable-hashing", ("no parameter appears to be injectable", "~is vulnerable to")), # same gate for --nosql (it used to report a "Lucene query_string-compatible back-end" from q=*)
("-u \"<base>xslt/element?tpl=x\" --xslt --flush-session --disable-hashing", ("is vulnerable to XSLT injection", "element context", "Engine: libxslt", "Type: XSLT injection", "XSLT scan complete")), # XSLT: the engine names itself through system-property('xsl:vendor') in the element slot - a value the application cannot produce on its own
("-u \"<base>xslt/value?sort=name\" --xslt --flush-session --disable-hashing", ("is vulnerable to XSLT injection", "value context", "XSLT compile-differential", "XSLT scan complete")), # XSLT: the value slot reflects nothing, so detection rests on the compile differential plus positive XPath-syntax evidence
("-u \"<base>xpath/search?q=x\" --xpath --flush-session --disable-hashing", ("is vulnerable to XPath injection", "Title: XPath boolean-based blind", "XPath: GET parameter 'q' XML tree", "extracted", "XPath scan complete")), # XPath: error-based detection + boolean oracle + blind XML tree-walking via starts-with character extraction
+7 -1
View File
@@ -12,6 +12,7 @@ from collections import namedtuple
from lib.core.common import beep
from lib.core.common import randomStr
from lib.core.common import removeReflectiveValues
from lib.core.convert import getUnicode
from lib.core.data import conf
from lib.core.data import logger
@@ -173,7 +174,12 @@ def _send(place, parameter, value):
# oracle sample - signal None so `_boolean`/`extract` (which reject None) can't decide on it
if blockedStatus(code):
return None
return page or ""
# Strip the payload back out before anything compares pages. An endpoint that merely ECHOES the
# parameter differs between any two probes because the payloads differ, which satisfies a
# true/false differential without a single expression being evaluated - that reported plain
# reflective search pages as injectable. On a blind target the payload is not in the page, so
# this is a no-op.
return removeReflectiveValues(page, value, suppressWarning=True) or ""
except Exception as ex:
logger.debug("LDAP probe request failed: %s" % getUnicode(ex))
return None
+7 -1
View File
@@ -14,6 +14,7 @@ from collections import OrderedDict
from lib.core.common import beep
from lib.core.common import randomStr
from lib.core.common import removeReflectiveValues
from lib.core.convert import getUnicode
from lib.utils.nonsql import userDecision
from lib.utils.nonsql import sqlErrorPresent
@@ -366,7 +367,12 @@ def _send(place, parameter, segment=None, jsonValue=_UNSET):
finally:
conf.skipUrlEncode = skipUrlEncode
return page or ""
# Strip the payload back out before anything compares pages. An endpoint that merely ECHOES the
# parameter differs between any two probes because the payloads differ, which satisfies a true/false
# differential - and the wildcard always-true check - without a single operator being interpreted.
# That reported a plain reflective search page as a "Lucene query_string-compatible back-end". On a
# blind target the payload is not in the page, so this is a no-op.
return removeReflectiveValues(page, payload, suppressWarning=True) or ""
def _isError(page):
# a server-error status, a recognizable NoSQL error body, OR a recognized SQL/DBMS error marks a