From 97c8b45ccc58c558e958677323677c994d8239d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20=C5=A0tampar?= Date: Sat, 11 Jul 2026 14:52:55 +0200 Subject: [PATCH] Minor patches --- lib/core/settings.py | 2 +- lib/utils/prove.py | 11 ++++++++++- lib/utils/sqlalchemy.py | 9 +++++++++ tamper/space2mssqlhash.py | 3 ++- 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 14c97ba34..cc83bda62 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.79" +VERSION = "1.10.7.80" 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/utils/prove.py b/lib/utils/prove.py index af11306c9..fccd275dc 100644 --- a/lib/utils/prove.py +++ b/lib/utils/prove.py @@ -347,6 +347,10 @@ def proveExploitation(): # back, exploitation is NOT proven; say so plainly instead of echoing the detection verdict. proven = bool(rungs) + # whether ANY confirmed technique here can return data inline; a stacked-query-only point cannot, so a + # failed read-back below is expected there and must NOT be spun into a "false positive" verdict + canReadBack = any(_ in injection.data for _ in (PAYLOAD.TECHNIQUE.BOOLEAN, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.TIME)) + if proven: if proof: fields.append(_field("Proof", proof)) @@ -361,7 +365,12 @@ def proveExploitation(): verdict = ["no value could be read back through the injection (tried a random arithmetic product and the DBMS banner)"] if suspectWaf: verdict.append("the TRUE/FALSE difference is only an HTTP %s (blocked) response - characteristic of a WAF/IPS, not a database answer" % signal.get("trueCode")) - if wafInterfering: + if not canReadBack: + # e.g. stacked-query-only: no confirmed technique returns data inline, so a value cannot be read + # back here - that is expected by design and is NOT evidence of a false positive + verdict.append("this injection point exposes no data-returning channel (e.g. stacked queries), so a value cannot be read back inline - expected here, not a false positive") + verdict.append("=> confirm exploitation through a side effect instead (e.g. '--os-shell', or '--sql-query' run with '--technique=S')") + elif wafInterfering: # behind a WAF, an unconfirmed read-back is ambiguous: a genuine injection whose data-retrieval # payloads are being blocked looks the same as a pure WAF artifact - so don't assert "false # positive", point the user at the way to disambiguate instead diff --git a/lib/utils/sqlalchemy.py b/lib/utils/sqlalchemy.py index d6d702ffc..8d8080141 100644 --- a/lib/utils/sqlalchemy.py +++ b/lib/utils/sqlalchemy.py @@ -131,6 +131,15 @@ class SQLAlchemy(GenericConnector): retVal = True except (_sqlalchemy.exc.OperationalError, _sqlalchemy.exc.ProgrammingError) as ex: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) + # Roll back the failed statement's transaction so it does not poison every following query with + # 'InFailedSqlTransaction' (SQLAlchemy 2.0+ keeps the transaction open after an error). Without this + # a single legitimately-failing probe - e.g. AURORA_VERSION() on vanilla PostgreSQL during + # fingerprinting - made all later queries silently return wrong values (e.g. '--is-dba' read False) + if hasattr(self.connector, "rollback"): + try: + self.connector.rollback() + except Exception: + pass except _sqlalchemy.exc.InternalError as ex: raise SqlmapConnectionException(getSafeExString(ex)) diff --git a/tamper/space2mssqlhash.py b/tamper/space2mssqlhash.py index befd6966e..880fdb8f9 100644 --- a/tamper/space2mssqlhash.py +++ b/tamper/space2mssqlhash.py @@ -15,11 +15,12 @@ def tamper(payload, **kwargs): Replaces space character (' ') with a pound character ('#') followed by a new line ('\n') Requirement: - * MSSQL * MySQL Notes: * Useful to bypass several web application firewalls + * The '#' single-line comment used here is MySQL-only (despite this script's legacy name); + T-SQL has no '#' comment, so it does not apply to Microsoft SQL Server >>> tamper('1 AND 9227=9227') '1%23%0AAND%23%0A9227=9227'