From 9925adf7997927c1d21382c5a2169427b6f8efc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20=C5=A0tampar?= Date: Tue, 21 Jul 2026 13:33:53 +0200 Subject: [PATCH] Adding tamper script sign --- lib/controller/checks.py | 31 ++++++++++++++++---------- lib/core/settings.py | 2 +- tamper/sign.py | 47 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 13 deletions(-) create mode 100644 tamper/sign.py diff --git a/lib/controller/checks.py b/lib/controller/checks.py index 473e5719b..533a157c6 100644 --- a/lib/controller/checks.py +++ b/lib/controller/checks.py @@ -1061,29 +1061,36 @@ def checkFilteredChars(injection): # inference techniques depend on character '>' if not any(_ in injection.data for _ in (PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.QUERY)): if not checkBooleanExpression("%d>%d" % (randInt + 1, randInt)): - # '>' is filtered - blind inference bisection (e.g. ASCII(...)>N) would silently - # retrieve nothing. Auto-apply the 'between' tamper (> -> NOT BETWEEN 0 AND, SQL - # standard, all DBMS) and re-verify, so the run adapts in place instead of forcing a - # manual rerun. Skipped when the user chose their own '--tamper' (respect that choice). - adapted = False + # '>' is filtered - blind inference (bisection and the count/length integer retrievals + # all rely on '>') would silently retrieve nothing. Cascade through the '>'-free + # comparison rewrites and adopt the first that RE-VERIFIES working, so the run adapts in + # place instead of forcing a manual rerun: 'between' (> -> NOT BETWEEN 0 AND) first, + # then 'greatest' (GREATEST()-based) for when BETWEEN itself is filtered. Skipped when the + # user chose their own '--tamper' (respect that choice). + adapted = None if not conf.tamper: from lib.utils.wafbypass import loadTamper - function = loadTamper("between") - if function is not None and function not in (kb.tamperFunctions or []): + for name in ("between", "greatest", "sign"): + function = loadTamper(name) + if function is None or function in (kb.tamperFunctions or []): + continue + kb.tamperFunctions = (kb.tamperFunctions or []) + [function] _ = randomInt() if checkBooleanExpression("%d>%d" % (_ + 1, _)): - adapted = True - infoMsg = "the character '>' appears to be filtered by the back-end " - infoMsg += "server; sqlmap automatically applied the 'between' tamper script to adapt" - logger.info(infoMsg) + adapted = name + break else: kb.tamperFunctions.remove(function) - if not adapted: + if adapted: + infoMsg = "the character '>' appears to be filtered by the back-end server; " + infoMsg += "sqlmap automatically applied the '%s' tamper script to adapt" % adapted + logger.info(infoMsg) + else: warnMsg = "it appears that the character '>' is " warnMsg += "filtered by the back-end server. You are strongly " warnMsg += "advised to rerun with the '--tamper=between'" diff --git a/lib/core/settings.py b/lib/core/settings.py index d042eda90..0601a6164 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.168" +VERSION = "1.10.7.169" 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/tamper/sign.py b/tamper/sign.py new file mode 100644 index 000000000..ff15c5c8e --- /dev/null +++ b/tamper/sign.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org) +See the file 'LICENSE' for copying permission +""" + +import re + +from lib.core.enums import PRIORITY + +__priority__ = PRIORITY.HIGHEST + +def dependencies(): + pass + +def tamper(payload, **kwargs): + """ + Replaces greater than operator ('>') with 'SIGN' counterpart (e.g. SIGN((A)-(B))=1) + + Tested against: + * MySQL 5 + * Oracle 11g + * PostgreSQL 9 + * Microsoft SQL Server 2012 + + Notes: + * Useful to bypass filtering of comparison operators altogether (>, <, + >=, <=), as SIGN() needs none of them - only subtraction and '='. + sqlmap's blind inference always compares a numeric ordinal against an + integer literal, so SIGN((A)-(B))=1 is an exact equivalent of A>B + there (no NULL/decimal/date/collation/overflow concerns in that domain) + + >>> tamper('1 AND A > B') + '1 AND SIGN((A)-(B))=1' + """ + + retVal = payload + + if payload: + match = re.search(r"(?i)(\b(AND|OR)\b\s+)([^><]+?)\s*(?!])>(?!=)\s*(\w+|'[^']+')", payload) + + if match: + _ = "%sSIGN((%s)-(%s))=1" % (match.group(1), match.group(3), match.group(4)) + retVal = retVal.replace(match.group(0), _) + + return retVal