Minor update for SQLlinter
Some checks are pending
/ build (macos-latest, 3.8) (push) Waiting to run
/ build (ubuntu-latest, pypy-2.7) (push) Waiting to run
/ build (windows-latest, 3.14) (push) Waiting to run

This commit is contained in:
Miroslav Štampar 2026-07-12 20:27:37 +02:00
parent 5f99b283c2
commit 0338c13063
3 changed files with 45 additions and 1 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.7.101"
VERSION = "1.10.7.102"
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

@ -75,6 +75,16 @@ _BINARY_SYMBOLS = frozenset(("=", "<>", "!=", "<", ">", "<=", ">=", "/", "%", "|
# "a,limit,b" would false-positive.
_CLAUSE_KEYWORDS = frozenset(("FROM", "WHERE", "HAVING", "INTO"))
# single-occurrence clause keywords (at most one per SELECT scope) with no
# identifier-collision risk - unlike GROUP/ORDER, which double as column names.
# a repeat at the same paren-depth is the 'WHERE x WHERE y' structural bug (e.g.
# a schema filter appended onto a base query that already carries a WHERE).
_SINGLE_CLAUSE_KEYWORDS = frozenset(("WHERE", "HAVING"))
# set operators that begin a fresh SELECT, resetting single-occurrence clauses at
# the current scope ('a WHERE x UNION b WHERE y' is legal; two WHEREs are not).
_SET_OPERATORS = frozenset(("UNION", "EXCEPT", "INTERSECT", "MINUS"))
# sqlmap's own templating markers. If any survives into a *final* outbound payload
# a substitution failed upstream (agent.py / cleanupPayload / queries.xml) - always
# a bug. Matched on the raw payload because a marker can leak anywhere (bare, inside
@ -309,6 +319,10 @@ def checkSanity(sql, keywords=None):
True
>>> bool(checkSanity("1UNION SELECT NULL"))
True
>>> bool(checkSanity("SELECT a FROM t WHERE x=1 WHERE y=2"))
True
>>> checkSanity("SELECT a FROM t WHERE x=1 UNION SELECT b FROM u WHERE y=2")
[]
"""
if not sql:
return []
@ -419,4 +433,28 @@ def checkSanity(sql, keywords=None):
if cur.type == T_OTHER:
issues.append("stray character '%s' at offset %d" % (cur.value, cur.start))
# -- duplicated single-occurrence clause at one scope ('WHERE x WHERE y') --
# WHERE/HAVING may appear at most once per SELECT scope; a second one at the
# same paren-depth (no set operator or ';' resetting the SELECT in between)
# is a structural impossibility no surrounding query can undo - subquery
# clauses live at a deeper depth and reset on '(' / ')'.
scopeSeen = [set()]
for token in sig:
if token.type == T_LPAREN:
scopeSeen.append(set())
elif token.type == T_RPAREN:
if len(scopeSeen) > 1:
scopeSeen.pop()
elif token.type == T_SEMI:
scopeSeen = [set()]
elif token.type == T_KEYWORD:
word = token.value.upper()
if word in _SINGLE_CLAUSE_KEYWORDS:
if word in scopeSeen[-1]:
issues.append("duplicate '%s' clause at offset %d" % (word, token.start))
else:
scopeSeen[-1].add(word)
elif word in _SET_OPERATORS:
scopeSeen[-1].clear()
return issues

View file

@ -66,6 +66,9 @@ DIALECT_GOOD = (
"SELECT LIMIT 0 1 DISTINCT(user) FROM INFORMATION_SCHEMA.SYSTEM_USERS", # HSQLDB space-LIMIT
"SELECT TOP 1 name FROM master..sysdatabases", # MSSQL TOP + db..table
"CONCAT('\\',0x71,(SELECT 1))", # backslash-literal string (ANSI)
"SELECT a FROM t WHERE x=1 UNION SELECT b FROM u WHERE y=2", # two WHEREs across UNION (legal)
"SELECT a FROM (SELECT b FROM t WHERE c=1) z WHERE d=2", # subquery WHERE + outer WHERE (different scopes)
"SELECT a FROM t WHERE x IN (SELECT c FROM d WHERE e=1) AND f=2", # WHERE with a WHERE'd subquery
)
# malformed fragments/statements that MUST flag
@ -92,6 +95,9 @@ BAD = (
"1 UNION ALLSELECT NULL", # glued keyword after UNION
"1 AND ORD(MID((SELECT COUNT(x FROM t),1,1))>64", # unbalanced parentheses (dropped ')')
"1 UNION ALL SELECT ,CONCAT(0x71,a,0x71) FROM t", # comma right after SELECT
"SELECT OWNER,OBJECT_NAME FROM SYS.ALL_OBJECTS WHERE OBJECT_TYPE IN ('TABLE','VIEW') WHERE OWNER IN ('APPU')", # double WHERE (mis-appended schema filter)
"SELECT tabschema,tabname FROM syscat.tables WHERE type IN ('T','V') WHERE tabschema IN ('DB2INST1')", # double WHERE (DB2)
"SELECT a FROM t WHERE x=1 HAVING c>1 HAVING d<2", # duplicate HAVING
)
# cross-dialect valid constructs the near-keyword / comma / digit-glue rules must