Expanding capabilities of MySQL to correctly retrieve UTF8MB4 chars

This commit is contained in:
Miroslav Štampar 2026-07-27 11:35:14 +02:00
parent 69108bcf01
commit ec58f57fa9
6 changed files with 18 additions and 3 deletions

View file

@ -527,6 +527,9 @@ class Agent(object):
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

View file

@ -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"

View file

@ -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

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.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)

View file

@ -672,8 +672,8 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=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'):

View file

@ -95,6 +95,14 @@ class Fingerprint(GenericFingerprint):
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 @@ class Fingerprint(GenericFingerprint):
hashDBWrite(HASHDB_KEYS.DBMS_FORK, fork)
self._checkUtf8mb4()
value = ""
wsOsFp = Format.getOs("web server", kb.headersFp)