Самое лучшее для исследователя в области баг-баунти, — это знания, который предоставляет сам процесс анализа.
Если помимо работы инженером в области безопасности вы занимаетесь баг-баунти в свободное время, всегда старайтесь применять полученные знания в своей основной работе, внедряя соответствующие механизмы защиты. Кроме того, делитесь своими находками с сообществом информационной безопасности через блоги и публикации.
Целью атаки стала платформа онлайн-образования, на которой была реализована аутентификация через OTP (одноразовый пароль). Когда речь идёт о входе с использованием OTP, первое, что приходит в голову: «Как это обойти?».
Сначала я попытался использовать метод перебора (brute force) и обнаружил, что была реализована защита с ограничением частоты запросов на основе IP-адреса. Это означает, что изменение IP-адреса клиента или IP-адреса, представляемого серверу, может помочь обойти это ограничение и продолжить перебор OTP.
Если клиент находится за прокси-сервером, прокси передаёт IP-адрес клиента серверу через специальный заголовок X-Forwarded-For. В некоторых случаях клиент может использовать этот заголовок для подделки своего IP-адреса.
Я попробовал сделать то же самое, добавил заголовок X-Forwarded-For, передал его в Intruder для брутфорса OTP для заданного номера телефона с варьирующимися IP-адресами и установил Cluster Bomb в качестве типа атаки для брутфорса.
Как и ожидалось, мне удалось выполнить брутфорс OTP и добиться успешного входа через OTP. Теперь настало время провести горизонтальную эскалацию привилегий. Было очевидно, что имеется уязвимость Header Injection, поэтому, помимо обхода IP-контроля или ограничения скорости, могли быть и другие возможности для эксплуатации. Я решил использовать подход со свей предыдущей организации, где мы ограничивали доступ к административным интерфейсам WordPress только для внутренних IP-адресов на основе IP-адреса клиента. Вот как это работает:
Если в значение заголовка указать разрешённый внутренний IP-адрес, прокси передаст значение заголовка X-Forwarded-For, даже если соединение фактически было установлено с IP-адреса, не входящего в список разрешённых. Это позволит атакующему получить доступ к ограниченной странице или API-эндпоинту.
Если установить заголовок X-Forwarded-For: 127.0.0.1, сервер будет считать, что доступ осуществляется с внутреннего IP-адреса, и позволит пользователю получить доступ к ограниченному контенту. Однако для этого нужно быть счастливчиком, чтобы найти такие ограниченные страницы. Обычно это административные страницы, панели администраторов или чувствительные эндпоинты.
Я попробовал получить доступ к админке WordPress на wp-admin — и получил ответ 200 OK!
Теперь оставалось лишь выполнить перебор директорий, чтобы найти другие точки с ограничением по IP-адресу. Нашёл несколько полезных ресурсов для поиска таких эндпоинтов и передал их Intruder для выполнения задачи:
К счастью, среди всех этих точек я нашёл одну административную страницу их CMS-каталога, которая вернула статус 200 OK (/cms/_admin/logon.php). И, помимо этого, я успешно выполнил горизонтальную эскалацию привилегий (хотя я не пытался войти в портал, чтобы проверить это на более высоком уровне).
Возможные решения
Разрешить указание списка IP-адресов (или CIDR) доверенных прокси и балансировщиков нагрузки. Если запрос не поступил от одного из них, отклонить заголовок X-Forwarded-For. Вот как это делает Nginx: он проверяет список (начиная с последней записи) и проверяет каждый элемент на предмет того, является ли он частью списка доверенных прокси. Когда встречается элемент, который не находится в списке, отклоняется всё, что до него.
Это всё, чему я научился в ходе этой интересной работы, где для обхода IP-ограничений на основе частоты использовалась Header Injection (X-Forwarded-For), что в дальнейшем позволило мне получить доступ к ограниченным эндпоинтам.
Комментарии (4)
GritsanY
07.12.2024 20:45Я не совсем понял. Reverse proxy NginX получается, по дефолту если получает легитимный пакет, то записывает IP адрес клиента в заголовок X-Forwarded-For. А если прилетает пакет нелегитимный уже с заголовком, установленным злоумышленником, он его просто пропускает дальше и не трогает?
YegorP
Кто так OTP делает вообще? Там сессия должна быть, в рамках которой даётся несколько попыток.
Mausglov
Для защиты от перебора OTP сессия не поможет. Как только попыткии исчерпаются, атакующий меняет IP в X-Forwarded-For и стартует новую сессию.
А за дырку с незащищённым доступом с внутренних IP автору спасибо. Никогда не думал в таком ключе.
YegorP
Как это не поможет? Новая сессия запустится уже с новыми кодами. Сколько таких сессий придётся создать чтобы в одной из них код совпал с тем, который подставляет атакующий? Это что-то вроде подбора в случайном порядке. В чистом виде это уязвимо, но в рамках сессии проще тормозить перебор и противодействовать перехвату логина (когда юзер вводит верный пароль, а атакующий с другого клиента перебирает OTP). Поэтому добавляем сюда задержку проверки на пару секунд, предотвращаем параллельные сессии, и всё. Это уже далеко от тривиального перебора 4-6-значных кодов. Поверх этого базового механизма уже прикручивается вторичная защита: рейт лимит по айпи, локаут, капча и алерты админам.