Fixing limitCondition double-LIMIT

This commit is contained in:
Miroslav Štampar 2026-07-28 16:24:22 +02:00
parent f992e44fb5
commit e8a2fc50e0
3 changed files with 24 additions and 3 deletions

View file

@ -1041,8 +1041,14 @@ class Agent(object):
else:
limitRegExp2 = None
# DBMSes whose paging is a simple appended "LIMIT ... OFFSET ..." (limitQuery '% (1, num)' group,
# limitregexp 'query2' for a bare LIMIT, groupstart=2/stop=1): a user-supplied LIMIT must be parsed
# AND stripped here, else limitQuery appends a SECOND LIMIT (e.g. '... LIMIT 3 LIMIT 1 OFFSET n' on
# ClickHouse) and per-row extraction (blind/error) reads bogus offsets - only UNION was unaffected.
limitOffsetAppendDbmses = (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE, DBMS.H2, DBMS.CLICKHOUSE, DBMS.CRATEDB, DBMS.SPANNER, DBMS.HANA)
if (limitRegExp or limitRegExp2) or (Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE) and topLimit):
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE, DBMS.H2):
if Backend.getIdentifiedDbms() in limitOffsetAppendDbmses:
limitGroupStart = queries[Backend.getIdentifiedDbms()].limitgroupstart.query
limitGroupStop = queries[Backend.getIdentifiedDbms()].limitgroupstop.query
@ -1084,7 +1090,7 @@ class Agent(object):
# From now on we need only the expression until the " LIMIT "
# (or equivalent, depending on the back-end DBMS) word
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE):
if Backend.getIdentifiedDbms() in limitOffsetAppendDbmses:
stopLimit += startLimit
if expression.find(queries[Backend.getIdentifiedDbms()].limitstring.query) > 0:
_ = expression.index(queries[Backend.getIdentifiedDbms()].limitstring.query)

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.7.220"
VERSION = "1.10.7.222"
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

@ -460,6 +460,21 @@ class TestLimitQuery(DbmsStateMixin, unittest.TestCase):
self.assertIn("NOT IN", out.upper(), msg=out)
class TestLimitConditionUserLimit(DbmsStateMixin, unittest.TestCase):
"""A user LIMIT in --sql-query must be parsed AND stripped for the 'append LIMIT/OFFSET'
DBMSes, else limitQuery appends a 2nd LIMIT and blind/error read bogus offsets."""
APPEND_DBMSES = (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE, DBMS.H2, DBMS.CLICKHOUSE, DBMS.CRATEDB, DBMS.SPANNER, DBMS.HANA)
def test_user_limit_stripped_and_parsed(self):
for dbms in self.APPEND_DBMSES:
set_dbms(dbms)
expression, limitCond, _, startLimit, stopLimit = agent.limitCondition("SELECT name FROM t ORDER BY y LIMIT 3")
self.assertTrue(limitCond, msg=dbms)
self.assertEqual((startLimit, stopLimit), (0, 3), msg=dbms)
self.assertIsNone(re.search(r"(?i)\bLIMIT\b", expression), msg="%s not stripped: %s" % (dbms, expression))
class TestWhereQuery(DbmsStateMixin, unittest.TestCase):
"""whereQuery only acts when conf.dumpWhere is set."""