Skip to content

Commit aa8d9b9

Browse files
committed
Patching non-SQLi techniques regarding reflective values
1 parent 61ffadb commit aa8d9b9

5 files changed

Lines changed: 31 additions & 3 deletions

File tree

extra/vulnserver/vulnserver.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1194,6 +1194,18 @@ def do_REQUEST(self):
11941194
self.wfile.write(output.encode(UNICODE_ENCODING))
11951195
return
11961196

1197+
if self.url == "/echo":
1198+
# A pure reflector: no engine of any kind behind it, it only shows the parameter back. Every
1199+
# non-SQL switch must stay silent here. A differential built on "the page changed" is
1200+
# satisfied by reflection alone, which is how several engines reported this shape as
1201+
# injectable - so this endpoint is the regression gate for that whole class.
1202+
self.send_response(OK)
1203+
self.send_header("Content-type", "text/html; charset=%s" % UNICODE_ENCODING)
1204+
self.send_header("Connection", "close")
1205+
self.end_headers()
1206+
self.wfile.write(("<html><body>you searched for: %s</body></html>" % self.params.get("q", "")).encode(UNICODE_ENCODING))
1207+
return
1208+
11971209
if self.url in ("/xslt/element", "/xslt/value"):
11981210
# VULNERABLE: user input is concatenated into a stylesheet which is then compiled and applied
11991211
element = self.url.endswith("element")

lib/core/settings.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from thirdparty import six
2121

2222
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
23-
VERSION = "1.10.8.14"
23+
VERSION = "1.10.8.15"
2424
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
2525
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34}
2626
VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE)

lib/core/testing.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,10 @@ def vulnTest(tests=None, label="vuln"):
9696
("-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
9797
("-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)
9898
("-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
99+
("-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
100+
("-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)
101+
("-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)
102+
("-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=*)
99103
("-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
100104
("-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
101105
("-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

lib/techniques/ldap/inject.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
from lib.core.common import beep
1414
from lib.core.common import randomStr
15+
from lib.core.common import removeReflectiveValues
1516
from lib.core.convert import getUnicode
1617
from lib.core.data import conf
1718
from lib.core.data import logger
@@ -173,7 +174,12 @@ def _send(place, parameter, value):
173174
# oracle sample - signal None so `_boolean`/`extract` (which reject None) can't decide on it
174175
if blockedStatus(code):
175176
return None
176-
return page or ""
177+
# Strip the payload back out before anything compares pages. An endpoint that merely ECHOES the
178+
# parameter differs between any two probes because the payloads differ, which satisfies a
179+
# true/false differential without a single expression being evaluated - that reported plain
180+
# reflective search pages as injectable. On a blind target the payload is not in the page, so
181+
# this is a no-op.
182+
return removeReflectiveValues(page, value, suppressWarning=True) or ""
177183
except Exception as ex:
178184
logger.debug("LDAP probe request failed: %s" % getUnicode(ex))
179185
return None

lib/techniques/nosql/inject.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
from lib.core.common import beep
1616
from lib.core.common import randomStr
17+
from lib.core.common import removeReflectiveValues
1718
from lib.core.convert import getUnicode
1819
from lib.utils.nonsql import userDecision
1920
from lib.utils.nonsql import sqlErrorPresent
@@ -366,7 +367,12 @@ def _send(place, parameter, segment=None, jsonValue=_UNSET):
366367
finally:
367368
conf.skipUrlEncode = skipUrlEncode
368369

369-
return page or ""
370+
# Strip the payload back out before anything compares pages. An endpoint that merely ECHOES the
371+
# parameter differs between any two probes because the payloads differ, which satisfies a true/false
372+
# differential - and the wildcard always-true check - without a single operator being interpreted.
373+
# That reported a plain reflective search page as a "Lucene query_string-compatible back-end". On a
374+
# blind target the payload is not in the page, so this is a no-op.
375+
return removeReflectiveValues(page, payload, suppressWarning=True) or ""
370376

371377
def _isError(page):
372378
# a server-error status, a recognizable NoSQL error body, OR a recognized SQL/DBMS error marks a

0 commit comments

Comments
 (0)