diff --git a/src/pentesting-web/unicode-injection/README.md b/src/pentesting-web/unicode-injection/README.md index 143f2116ff7..08e8433da0c 100644 --- a/src/pentesting-web/unicode-injection/README.md +++ b/src/pentesting-web/unicode-injection/README.md @@ -4,66 +4,184 @@ ## Introduction -Depending on how the back-end/front-end is behaving when it **receives weird unicode characters** an attacker might be able to **bypass protections and inject arbitrary characters** that could be used to **abused injection vulnerabilities** such as XSS or SQLi. +Depending on how the back-end/front-end behaves when it **receives weird Unicode characters**, an attacker might be able to **bypass protections and inject arbitrary ASCII metacharacters later**. The dangerous pattern is usually: -## Unicode Normalization +1. Input is validated in one representation +2. The application or database **implicitly converts / normalizes / re-encodes** it +3. The converted value becomes dangerous **after** validation -Unicode normalization occurs when **unicode characters are normalized to ascii characters**. +This can turn apparently harmless input into working payloads for **XSS, SQLi, path traversal/LFI, command injection, or logic bugs**. -One common scenario of this type of vulnerability occurs when the system is **modifying** somehow the **input** of the user **after having checked it**. For example, in some languages a simple call to make the **input uppercase or lowercase** could normalize the given input and the **unicode will be transformed into ASCII** generating new characters.\ -For more info check: +## Unicode normalization + +Unicode normalization occurs when **Unicode characters are normalized to ASCII characters** or to another compatible representation. One common scenario is when the system **modifies** the user input **after checking it**. For example, in some languages a simple call to make the **input uppercase or lowercase** could normalize the given input and the **Unicode will be transformed into ASCII** generating new characters. +For more info check: {{#ref}} unicode-normalization.md {{#endref}} -## `\u` to `%` +## SQL Server Best Fit / implicit conversion -Unicode characters are usually represented with the **`\u` prefix**. For example the char `㱋` is `\u3c4b`([check it here](https://unicode-explorer.com/c/3c4B)). If a backend **transforms** the prefix **`\u` in `%`**, the resulting string will be `%3c4b`, which URL decoded is: **`<4b`**. And, as you can see, a **`<` char is injected**.\ -You could use this technique to **inject any kind of char** if the backend is vulnerable.\ -Check [https://unicode-explorer.com/](https://unicode-explorer.com/) to find the chars you need. +Microsoft SQL Server adds another dangerous post-validation transform: **implicit conversion from Unicode strings to narrow non-UTF code pages** (`char`, `varchar`, `text`, or non-Unicode string literals). Instead of rejecting unsupported characters, SQL Server can silently apply **Windows Best Fit mapping** and mutate Unicode lookalikes into ASCII metacharacters. -This vuln actually comes from a vulnerability a researcher found, for a more in depth explanation check [https://www.youtube.com/watch?v=aUsAHb0E7Cg](https://www.youtube.com/watch?v=aUsAHb0E7Cg) +### Dangerous conditions -## Emoji Injection +Look for combinations such as: -Back-ends something behaves weirdly when they **receives emojis**. That's what happened in [**this writeup**](https://medium.com/@fpatrik/how-i-found-an-xss-vulnerability-via-using-emojis-7ad72de49209) where the researcher managed to achieve a XSS with a payload such as: `💋img src=x onerror=alert(document.domain)//💛` +- Columns using **`varchar` / `char` / `text`** +- Non-UTF collations / code pages such as CP1252 (`iso_1` in metadata) +- **Implicit conversion** from `nvarchar` to `varchar` +- Dynamic SQL using **non-Unicode literals** like `'payload'` instead of `N'payload'` +- Security-sensitive comparisons under **case-insensitive collations** such as `*_CI_*` -In this case, the error was that the server after removing the malicious characters **converted the UTF-8 string from Windows-1252 to UTF-8** (basically the input encoding and the convert from encoding mismatched). Then this does not give a proper < just a weird unicode one: `‹`\ -``So they took this output and **converted again now from UTF-8 ot ASCII**. This **normalized** the `‹`to`<` this is how the exploit could work on that system.\ -This is what happened: +Useful recon queries: -```php - < +-- wide => < ``` -Emoji lists: +This is not Unicode normalization in the standard sense; it is **Windows code-page Best Fit conversion** during SQL Server storage/conversion. -- [https://github.com/iorch/jakaton_feminicidios/blob/master/data/emojis.csv](https://github.com/iorch/jakaton_feminicidios/blob/master/data/emojis.csv) -- [https://unicode.org/emoji/charts-14.0/full-emoji-list.html](https://unicode.org/emoji/charts-14.0/full-emoji-list.html) +### Non-Unicode literal pitfall -## Windows Best-Fit/Worst-fit +In SQL Server, `'text'` is a **non-Unicode literal by default**, even when inserted into an `NVARCHAR` column. Use the `N` prefix for wide strings: -As explained in **[this great post](https://blog.orange.tw/posts/2025-01-worstfit-unveiling-hidden-transformers-in-windows-ansi/)**, Windows has a feature called **Best-Fit** which will **replace unicode characters** that cannot be displayed in ASCII mode with a similar one. This can lead to **unexpected behavior** when the backend is **expecting a specific character** but it receives a different one. +```sql +INSERT INTO t VALUES ('<'); -- converted before assignment +INSERT INTO t VALUES (N'<'); -- preserved in NVARCHAR, still mutated in VARCHAR +``` -It's possible to find best-fit characters in **[https://worst.fit/mapping/](https://worst.fit/mapping/)**. +This matters in **stored procedures**, **dynamic SQL**, and any code path that concatenates attacker-controlled strings into SQL statements. -As Windows will usually convert unicode strings to ascii strings as one of the last parts of the execution (usually going from a "W" suffixed API to an "A" suffixed API like `GetEnvironmentVariableA` and `GetEnvironmentVariableW`) this would allow atackers to bypass protections by sending unicode characters that will be converted lastly in ASCII characters that would perform nuexpected actions. +### Stored XSS after DB storage -In the blog post there are proposed methods to bypass vulnerabilities fixed using a **blacklist of chars**, exploit **path traversals** using [characters mapped to “/“ (0x2F)](https://worst.fit/mapping/#to%3A0x2f) and [characters mapped to “\“ (0x5C)](https://worst.fit/mapping/#to%3A0x5c) or even bypassing shell escape protections like PHP's `escapeshellarg` or Python's `subprocess.run` using a list, this was done for example using **fullwidth double quotes (U+FF02)** instead of double quotes so at the end what looked like 1 argument was transformed in 2 arguments. +If an application filters classic ASCII XSS but accepts Unicode lookalikes, SQL Server can convert them into a valid payload **after insertion**: -**Note that for an app to be vulnerable it needs to use "W" Windows APIs but end calling an "A" Windows api so the "Best-fit" of the unicode string is created.** +```sql +CREATE TABLE worstfitx ( + vary VARCHAR(50) COLLATE French_CI_AS +); -**Several dicovered vulnerabilities won't be fixed as people don't agree who should be fixing this issue"**. +INSERT INTO worstfitx VALUES (N'〈script〉alert(ʹxʹ)〈/script〉'); +SELECT vary FROM worstfitx; +-- +``` -{{#include ../../banners/hacktricks-training.md}} +This is especially interesting when the app: + +- validates only before insert +- stores the payload in MSSQL +- later renders the **stored** value into HTML + +### Path traversal / LFI after DB storage + +If filenames are stored in narrow MSSQL columns and later reused to build filesystem paths, Unicode dots and slash/backslash lookalikes can turn into traversal sequences: + +```sql +CREATE TABLE worstfity ( + id SMALLINT, + file_name VARCHAR(50) COLLATE French_CI_AS +); + +INSERT INTO worstfity +VALUES (45, N'..∖..∖..∖Windows∖win.ini'); + +SELECT file_name FROM worstfity WHERE id = 45; +-- ..\..\..\Windows\win.ini +``` + +The filter may only see the Unicode version, while the application later consumes the **mutated** Windows path from the database. + +### `?` fallback reconstruction + +When no Best Fit mapping exists, many Windows code pages fall back to `?`. This can reconstruct blocked syntax: + +```sql +INSERT INTO worstfitx VALUES (N'<ʭphp'); +SELECT vary FROM worstfitx; +-- `, `'`, `"`, `/`, `\`, `.`, `-`, `?` +- Compare **pre-insert** and **post-read** values, not only the reflected request +- Check whether the app uses **`VARCHAR` metadata + Unicode client input** +- Probe both `'payload'` and `N'payload'` +- Audit logic bugs caused by `*_CI_*` collations in addition to injection sinks + +## `\u` to `%` + +Unicode characters are usually represented with the **`\u` prefix**. For example the char `㱋` is `\u3c4b` ([check it here](https://unicode-explorer.com/c/3c4B)). If a backend **transforms** the prefix **`\u` into `%`**, the resulting string will be `%3c4b`, which URL decoded is **`<4b`**. As you can see, a **`<` char is injected**. +You could use this technique to **inject any kind of char** if the backend is vulnerable. Check [https://unicode-explorer.com/](https://unicode-explorer.com/) to find the chars you need. +This vuln actually comes from a vulnerability a researcher found. For a more in-depth explanation check [https://www.youtube.com/watch?v=aUsAHb0E7Cg](https://www.youtube.com/watch?v=aUsAHb0E7Cg) + +## Emoji injection + +Back-ends sometimes behave weirdly when they **receive emojis**. That's what happened in [this writeup](https://medium.com/@fpatrik/how-i-found-an-xss-vulnerability-via-using-emojis-7ad72de49209) where the researcher managed to achieve XSS with a payload such as `img src=x onerror=alert(document.domain)//`. + +In that case, the server removed malicious characters and then **converted the UTF-8 string from Windows-1252 to UTF-8** (input/convert encoding mismatch). This did not immediately generate a proper `<`, just a weird Unicode quote-like character: `‹`. + +Then the output was **converted again from UTF-8 to ASCII**. This second conversion normalized `‹` into `<`, making the payload executable: + +```php + +``` + +## References + +- [Synacktiv - The SQL Server Unicode problem: why your data might not be what you think it is?](https://synacktiv.com/en/publications/the-sql-server-unicode-problem-why-your-data-might-not-be-what-you-think-it-is.html) +- [HackTricks - Unicode normalization](unicode-normalization.md) +- [Unicode Explorer](https://unicode-explorer.com/) +- [Orange Tsai / DEVCORE - WorstFit: Unveiling Hidden Transformers in Windows ANSI!](https://devco.re/blog/2025/01/09/worstfit-unveiling-hidden-transformers-in-windows-ansi/) +{{#include ../../banners/hacktricks-training.md}}