Skip to content

SEC-T 0x11: noraj

PolicySEC-T 202532 minOpen on YouTube ↗

Explores SEC-T 0x11: noraj and evaluates key implications for security practitioners.

Summary

### Overview In this talk presented at SEC-T 0x11, Alexander (noraj), a pentester at Synactive and maintainer of BlackArch Linux, explores the security risks arising from Unicode's complexity and developers' lack of awareness. Because Unicode unifies older encoding standards and expands to millions of characters through mechanisms like code points, composition, and joining, naive implementations in software frequently lead to vulnerabilities.

### Key Topics - **Unicode Fundamentals**: Code points (represented standardly as `U+<hex>`), variable-length encodings such as UTF-8 (1 to 4 bytes), composing characters (e.g., combining diacritics), and joining characters (e.g., combining emojis or variation selectors). - **Visual and Source Code Attacks**: The use of homoglyphs and invisible control characters for phishing, typo-squatting, and backdoor insertion in source code. - **String Length and Sizing Pitfalls**: Discrepancies between human-visible graphemes, Unicode code points/units, and raw byte lengths across encodings like UTF-8, UTF-16, and UTF-32. - **Case Transformation Collisions**: Non-bijective casing behavior leading to string length changes, domain collisions, and account takeovers. - **Normalization Vulnerabilities**: Exploitation of Unicode normalization forms (NFD, NFC, NFKD, NFKC) to execute host splitting and bypass XSS sanitization.

### Technical Details - **Source Code Backdoors via Homoglyphs & Invisible Characters**: Alexander demonstrates substituting standard syntax operators with homoglyphs, such as replacing an exclamation mark (`!`) in JavaScript with a retroflex click character in a variable name, turning an equality check into a perpetual assignment (`true`). Invisible characters, like the Hangul filler inserted into a JavaScript equality check, can silently trigger unintended code evaluation without visual indication. - **Sizing Inconsistencies**: A single visible emoji composed of a woman, a joiner, a heart, a color variation selector, another joiner, and a man constitutes one grapheme but six code units, translating into differing byte counts across UTF-8, UTF-16, and UTF-32. Naive length queries in environments like Node.js can return surrogate-pair counts instead of grapheme counts, risking buffer overflows, string truncation, and misaligned sanitization indices. - **Case Transformation Exploits**: Uppercasing characters like the German Eszett (`ß`) expands one character into two (`SS`), while lowercasing the Kelvin sign (`K`) collapses it to a standard ASCII `k`. In an illustrated password reset flow, an attacker submits `synactive.com` containing the Kelvin sign. The application normalizes the input to lower case for database lookup (retrieving the legitimate admin's account), but dispatches the reset token using the un-lowercased email input, routing the reset email to an attacker-controlled domain. - **Host Splitting & XSS Filter Bypasses via Normalization**: In compatibility normalization modes (NFKD/NFKC), specific multi-character mappings—such as the "addressed to the subject" glyph normalizing to `a/s`—can split hostnames and turn what appeared to be a subdomain whitelist match (`synactive.<glyph>.target.com`) into an entirely different path and domain. Similarly, passing Unicode characters that transform into `<` or `>` under NFKC/NFKD after an HTML escape function has run allows filters to be bypassed. Alexander also illustrates how NFC recomposition can absorb closing delimiters into attribute values, triggering context breakouts.

### Takeaways Developers must recognize that Unicode operations—including casing, length measurement, and normalization—can mutate strings in non-trivial ways. Order of operations is critical: data normalization must always occur prior to escaping or validation to prevent mutated payloads from reintroducing dangerous syntax.

Related talks