MySQL Hexadecimal Strings
MySQL accepts hexadecimal literals as a native string representation — a feature with significant offensive value. When quote-based injection is blocked by escaping functions like PHP’s mysql_real_escape_string() or addslashes(), hex literals bypass the filter entirely because they require no quotes.
Syntax
MySQL supports two hex literal notations:
X'48656C6C6F' -- standard SQL notation (case-insensitive X)
0x48656C6C6F -- ODBC-style notation (0x must be lowercase)Both produce the binary string Hello. The X'val' notation requires an even number of hex digits; 0xval pads odd-length values with a leading zero.
Why it works
By default, a hexadecimal literal is a binary string, not a number. Each pair of hex digits maps to one byte. MySQL automatically decodes it in string contexts:
SELECT 0x68656C6C6F; -- returns "hello"
SELECT X'4D7953514C'; -- returns "MySQL"Because hex literals are not quoted strings, escaping functions that only neutralize ' and " have no effect on them. The payload passes through the filter intact and is decoded by MySQL at query time.
Offensive use
Bypassing quote filters. If the application escapes single quotes but passes hex input unfiltered, inject via hex:
-- Instead of: UNION SELECT 'admin'--
-- Use:
UNION SELECT 0x61646D696E--Concatenation without quotes. Build strings without ever touching a quote character:
SELECT CONCAT(0x61646D696E, 0x3A, 0x70617373); -- "admin:pass"Evading WAF keyword rules. Some WAFs flag common SQL keywords or quoted strings but miss hex-encoded equivalents.
GROUP_CONCAT separators. 0x3a is a colon, 0x2c is a comma — useful for building readable output from aggregated rows.
Converting to hex
echo -n "hello" | xxd -p | tr -d '\n'
# 68656c6c6fOr in Python: 'hello'.encode().hex() → 68656c6c6f.
Defensive note
Hex literal support cannot be disabled in MySQL. The defense is the same as for all SQLi: parameterized queries. Escaping functions are inherently incomplete — they protect against known-bad characters but cannot anticipate all valid SQL representations of attacker-controlled data.
Sources
- MySQL 8.0 Reference Manual — Hexadecimal Literals
- MySQL 8.0 Reference Manual — String Functions and Operators
- SQL Injection — OWASP
See also
- sql-injection-attacks — the hub page for SQLi types and defense
- mysql-ascii-function — complementary technique for blind extraction
- test-for-sqli — detection methodology
- enumerate-database-schemas — where hex strings are often needed
- php — the language where mysql_real_escape_string() appears