В некоторых системах одиночные Unicode-суррогаты работают необычно: валидатор пропускает их как обычные буквы, а внутренние сервисы преобразуют их в вопросительный знак.
В ряде баз данных
? — это wildcard. Так и возникает уязвимость, которая даёт доступ к данным 💭Юникод использует диапазон символов U+0000–U+10FFFF. Но старый формат UTF-16 не мог напрямую закодировать все символы выше U+FFFF, поэтому придумали специальный механизм — суррогаты. Есть два типа:
High surrogates — старшие суррогаты
Диапазон: U+D800–U+DBFF
Low surrogates — младшие суррогаты
Диапазон: U+DC00–U+DFFF
По отдельности они не являются валидными символами. Но если записать их пару (high + low), то вместе они кодируют один символ за пределами базовой области Unicode (например эмодзи).
Пример: эмодзи 😄 — это комбинация двух суррогатов в UTF-16.
Багхантер Krzysztof Balas нашел публичный эндпоинт, который отдавал данные пользователя, если ввести:
⚫️ дату рождения,
⚫️ фамилию,
⚫️ ZIP-код.
Авторизация не требовалась. После первого репорта разрабы закрыли все спецсимволы, URL-encoding и даже «юникодные аналоги» запрещённых символов.
Но осталось кое-что ещё — одиночные Unicode-суррогаты, например
\udc2a. Если отправить что-то вроде:"lastname": "D\udc2a\udc2a",
"zipcode": "1\udc2a\udc2a\udc2a\udc2a"
, то парсеры UTF-8 не смогут корректно отобразить Unicode-суррогаты, которые часто используются в эмодзи с low и high парами. Все, что ты получаешь при попытке их отобразить, — это символ замены Юникода.
Некоторые парсеры, по-видимому, идут еще дальше и упрощают символ замены до вопросительного знака (
?), что и приводит к возникновению уязвимости 💡


