Второй аргумент
postMessage определяет, какому origin разрешено получить данные. Браузер прогоняет это значение через свой URL-парсер перед любым сравнением, и парсер переписывает некоторые хосты.Хост, состоящий из простого числа, интерпретируется как IPv4 и записывается обратно в точечной нотации — так
2130706433 превращается в 127.0.0.1. Шестнадцатеричные, восьмеричные и короткие формы вроде 127.1 ведут себя аналогично.➡️ Уязвимый паттерн выглядит так: приложение принимает
origin от пользователя и проверяет его регуляркой вроде https?://[^.]+[.]target[.]com, рассчитывая пропустить только поддомены target.com — а затем передаёт проверенное значение в postMessage.Проблема в том, что
[^.]+ должен матчить одну метку поддомена, но проверяет он сырую строку целиком и не запрещает слэш — а слэш не точка. Это значит, что строка http://2130706433/.target.com тоже пройдёт проверку: [^.]+ жадно захватывает 2130706433/, а .target.com в конце удовлетворяет оставшейся части регулярки.В результате в код попадает такой вызов:
window.postMessage('message_here', 'http://2130706433/.target.com')
Однако это не является поддоменом чего-либо. После парсинга хост становится
2130706433, который нормализуется в 127.0.0.1, а /.target.com — это просто путь, который проверки origin игнорируют. Данные уходят на http://127.0.0.1, который контролирует атакующий 🤤URL Standard:
🔗 IPv4 parser
🔗 IPv4 serializer
@BugBountyRu 🕷 Буст каналу
