$$$$ за полный захват аккаунта (ATO), обход 2FA, утечку конфиденциальных данных через критические ошибки в CORS

от автора

Раньше я не имел привычки писать о своих находках, но теперь решил время от времени делиться наиболее интересными. Это мой первый разбор одной из моих последних находок, поэтому любые предложения или вопросы более чем приветствуются!

В этом разборе я покажу вам, как ошибка в конфигурации CORS привела к полному захвату аккаунта (ATO) и обходу двухфакторной аутентификации. Без лишних слов, перейдем к истории.

Я скрою название цели (довольно популярной), но отмечу, что один из ее сервисов связан с механизмом безопасности, предназначенным для защиты веб-сайтов и приложений при сохранении конфиденциальности пользователей. Этот механизм разработан для предотвращения автоматизированных злоупотреблений и атак, при этом обеспечивает легитимное взаимодействие с веб-сайтом без чрезмерного отслеживания или сбора данных.

Методология

Я не проводил никакой разведки, вместо этого я сразу сосредоточился на основном домене. Я начал с посещения страницы, чтобы создать новый аккаунт и завершить процесс регистрации.  

Цель предлагает различные тарифные планы, от бесплатных услуг до корпоративных решений. Я выбрал версию «Pro» и активировал бесплатный пробный период.  

После завершения регистрации я вошел в систему с использованием своих учетных данных и был перенаправлен на страницу. Там я начал изучать различные функции. В настройках профиля я активировал двухфакторную аутентификацию (2FA) и добавил ключ безопасности как дополнительный метод аутентификации, что позволяет входить в систему без ввода пароля каждый раз.  

Настроив аккаунт, я продолжил исследовать приложение как обычный пользователь, направляя трафик через Burp Suite.

После некоторого времени, проведенного в панели управления, в истории Burp я наткнулся на GET-запрос. Ответ содержал JSON с конфиденциальной информацией, включая тип пользователя, адрес электронной почты, зашифрованный email, параметры «избранное» и «забаненные».

Однако самая критическая проблема заключалась в том, что ответ также включал действительный токен сессии в заголовке ответа Set-Cookie — именно здесь начался настоящий хаос.

До этого момента все казалось довольно неплохим. Однако наличие Access-Control-Allow-Origin: https://accounts.target.com вместе с Access-Control-Allow-Credentials: true в ответе сервера сразу привлекло мое внимание. С этого момента я отложил все остальные идеи и начал проверять на наличие потенциальной проблемы с CORS.

Понимание неправильных конфигураций CORS и их влияние на безопасность

Описание

Cross-Origin Resource Sharing (CORS) — это механизм безопасности, применяемый веб-браузерами для контроля доступа к ресурсам из различных источников, который дополняет Same-Origin Policy (SOP).

Неправильные конфигурации возникают, когда сервер неправильно допускает кросс-доменные запросы, что потенциально может привести к раскрытию конфиденциальных данных при переходе на неизвестные сайты. Обычно это происходит, когда универсальные источники (*), доверенные поддомены или неправильно настроенные заголовки Access-Control-Allow-Origin и Access-Control-Allow-Credentials предоставляют непреднамеренный доступ. Злоумышленники могут использовать это, чтобы похитить данные пользователей, захватить сессии или выполнять несанкционированные действия от имени жертвы, обходя таким образом SOP защиту.

Исходный запрос и ответ выглядели так:

Я многократно изменял заголовок Origin, пытаясь проэксплуатировать неправильную конфигурацию CORS, но все мои попытки были отклонены — постоянный отказ в доступе неавторизованным источникам. Однако, когда я заменил заголовок Origin на домен, которому цель явно доверяет (перебрал список доверенных источников), я заметил, что он был отражен в ответе. Интересно, что это был единственный принятый субдомен.

Затем я повторил все свои предыдущие техники для изменения заголовка Origin, но ничего не изменилось. В каждом случае, когда источник был неверным, заголовки Access-Control-Allow-Origin и Access-Control-Allow-Credentials просто отсутствовали в ответе.

Прорыв произошел, когда я обнаружил, что добавление (конкатенация) любой строки к доверенному субдомену все равно приводит к тому, что запрос принимается. Это работало как с https, так и с http, например:

Origin: https://blablasub.target.com

Origin: http://blablasub.target.com

Этого было достаточно, чтобы подготовить доказательство концепции (proof of concept). Я создал XMLHttpRequest к уязвимому эндпоинту, включив учетные данные в запрос, и успешно прочитал конфиденциальный ответ с моего произвольного источника. Чтобы продемонстрировать влияние (impact), я разместил вредоносный скрипт на своем сервере, который отправляет запрос (https://blasub.target.com) для получения данных и извлечения ответа.

Скрипт выглядел следующим образом:

<!DOCTYPE html>

<html>

<body>

<center>

<h1>CORS PoC Exploit</h1>

<div id="demo">

<button type="button" onclick="cors()">Click Me</button>

</div>

</center>

<script>

function cors() {

  var xhttp = new XMLHttpRequest();

  xhttp.onreadystatechange = function() {

    if (this.readyState == 4 && this.status == 200) {

      document.getElementById("demo").innerHTML = alert(this.responseText);

    } else if (this.readyState == 4) {

      document.getElementById("demo").innerHTML = document.write("Error: " + this.status);

    }

  };

  var url = "https://accounts.target.com/auth/pro/allowed_accounts";

  xhttp.open("GET", url, true);

  xhttp.withCredentials = true;

  var requestBody = JSON.stringify({

  });

  xhttp.send(requestBody);

}

</script>

</body>

</html>

PoC с моего источника

На этом этапе у меня была неправильная конфигурация CORS, приводящая к раскрытию конфиденциальных данных произвольным источникам, что, скорее всего, будет принято как проблема средней или высокой степени серьезности. Однако вместо того чтобы немедленно сообщить об этом, я решил копнуть глубже, надеясь развить ситуацию в полный захват учетной записи (ATO).

Забавная заметка: Как видно на скриншоте выше, запрос требует отправки X-Csrf-Token, чтобы он прошел успешно. Однако я обнаружил, что полное исключение этого токена из запроса все равно позволяло мне получить корректный ответ — без какой-либо проверки аутентификации или авторизации! Это само по себе является отдельной уязвимостью, потому что мне не нужно было получать этот токен или пытаться его угадать.

Важная заметка: Всякий раз, когда вы сталкиваетесь с проблемой CORS, особенно если Origin динамически отображается в ответе, не торопитесь с отчетом — изучите проблему внимательнее. Возможно, вы обнаружите еще что-то более значимое.

Механизм входа в систему

Напомню, после активации 2fa (двухфакторной аутентификации) вход в приложение будет выполняться следующим образом:

1. Пользователь посещает https://target.com/login.

2. Приложение предлагает пользователю выбрать метод входа:

2.1. Аутентификация с помощью ключа доступа

  • Пользователь вводит ключ доступа (предопределенное слово, биометрическую верификацию и т.д.).

  • В случае успешного выполнения он входит в систему.

2.2. Двухфакторная аутентификация (2FA)

  • Пользователь вводит свой адрес электронной почты.

  • Пользователь вводит свой пароль.

  • Пользователь вводит код 2FA.

  • Если все шаги пройдены успешно, он входит в систему.

Предзахват учетной записи

Как упоминалось ранее, ответ содержит действительный session cookie, который помечен как HttpOnly, чтобы предотвратить доступ к нему с помощью JavaScript.

Обычно это защищает cookie от кражи через клиентские скрипты. Однако в моем случае сам ответ предоставлял сессионный токен в заголовке. Хотя cookie автоматически отправлялся с каждым запросом, сервер генерировал его заново в ответе, фактически раскрывая его. Это означало, что мне не нужно было использовать какой-либо язык серверной разработки для его извлечения — он уже был записан в логах моего сервера.

Захват учетной записи

Теперь я был всего в одном шаге от полного захвата учетной записи (ATO), так как при аутентификации пользователя, приложение полностью полагалось на этот сессионный cookie.

Получив его, я открыл новую вкладку в режиме инкогнито (используя другой браузер) и вручную внедрил cookie в хранилище браузера. После обновления страницы я успешно вошел в систему как жертва — получив полный контроль над учетной записью, полностью обойдя процесс аутентификации, включая 2FA и Passkey.

Вы, возможно, думаете о том же, о чем и я — может ли это быть ложноположительным срабатыванием? Чтобы проверить, я переключился на другую сеть с новым IP-адресом и повторил попытку, используя сессионный cookie.

Удивительно, но это всё ещё работало. Сессия оставалась действительной, что позволило мне снова войти в систему как жертва. Это было неожиданно, потому что, согласно политике безопасности приложения, сессионные токены должны были быть привязаны к IP-адресу и непригодны для повторного использования после входа. Очевидно, это было не так.

На этом этапе я задокументировал все детали и составил подробный отчет, в котором описал уязвимости и их потенциальное воздействие. Затем я сообщил компании о проблемах, чтобы они были в курсе рисков и могли предпринять соответствующие меры для их смягчения.

Хронология

  • Дата подачи: Среда, 19 февраля 2025 года — 10:26  

  • Первый ответ: Среда, 19 февраля 2025 года — 13:51  

  • Проблема обсуждена: Среда, 19 февраля 2025 года — 22:03 (Частичное исправление, устранена проблема с CORS)  

  • Исправления: Воскресенье, 9 марта 2025 года — 9:13  

  • Выплачено вознаграждение: $$$$ — Суббота, 14 марта 2025 года — 13:57  

  • Статус: ✅ Исправлено


ссылка на оригинал статьи https://habr.com/ru/articles/896684/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *