pub fn sql_char_decompose(payload: &str) -> StringExpand description
SQL CHAR()-function decomposition — converts every single-quoted string
literal in the payload to a CHAR(N1,N2,...) function call with one
codepoint per argument.
Input 'admin' → output CHAR(97,100,109,105,110)
Bypass mechanism: distinct from sql_concat_split (which produces
CONCAT('a','d',...)) — CHAR() takes integer codepoints, not single-
char strings, so the payload contains NO single-quoted ASCII tokens at
all. WAF rules that match string-literal patterns ('admin',
'password', '/etc/passwd', 'or 1') and CONCAT-shaped patterns
(CONCAT\(.{,8}\)) both miss this form. Most CRS rules through PL3 do
NOT pattern-match raw CHAR() — it’s been the sqlmap default for over a
decade and has been deemed too noisy to block.
Supported by MySQL, MariaDB (native CHAR()), MSSQL (CHAR()). For
Postgres / Oracle, the equivalent is CHR() — out of scope here; a
sibling chr_decompose could ship later.
Edge cases:
- Empty literals (
'') pass through as''unchanged.CHAR()with zero args evaluates to NULL in MySQL — silently flipping a comparison likepass='' OR 1=1intopass=NULL OR 1=1would break the auth bypass (= NULLis never TRUE). Preserve the empty-string identity. - Multi-byte UTF-8 chars produce a single
CHAR(codepoint)perchars()iteration — for codepoints > 255, MySQL’s CHAR() returns per-byte; the codepoint may not round-trip exactly. Most SQLi payloads use ASCII literals — this matters only for adversarial inputs. - Unbalanced opening quote: emitted unchanged.
Context: SQL injection with string-literal targets that are
blocklisted (admin, password, paths, hostnames).