flawopen.com/Incidents/capital-one-ssrf-imds-july-2019
Capital One: SSRF и кража учетных данных AWS IMDSv1
В федеральной жалобе утверждалось, что ошибочная настройка WAF позволила SSRF достичь AWS IMDSv1 и раскрыть временные учётные данные роли и данные S3 примерно 106 млн человек. Требуйте токены и ограничьте роли.[10], [2]
В уголовной жалобе DOJ описана такая цепочка: Представьте сотрудника на ресепшене, который приносит документы по указанным вами адресам. Пересылка запросов может позволить кому-то направить его во внутренний кабинет. Там он может получить временный пропуск для рабочей нагрузки; пропуск открывает только помещения, разрешённые связанной с ней ролью. Ошибка состояла в предположении, что в кабинет попадут только сотрудники, хотя туда можно было направить работника ресепшена.[10], [8]
Ключевые понятия и термины
SSRF- Подделка запросов на стороне сервера (
CWE-918): заставить сервер отправить выбранный злоумышленником запрос, который получает сетевое положение и доверие сервера.[9] Межсетевой экран веб-приложений- Фильтр перед веб-приложением. В уголовной жалобе утверждалось, что неправильно настроенный WAF Capital One пересылал запросы на внутренние адреса.[10]
IMDSv1- Когда IMDSv1 включён, запросы метаданных не требуют токена. Путь учётных данных безопасности IAM-роли возвращает временные учётные данные этой роли.[7], [8]
IMDSv2- В IMDSv2 используется токен сеанса, получаемый запросом PUT. Задайте
HttpTokens=required, чтобы отклонять запросы IMDSv1 без токена; это блокирует многие SSRF-ретрансляторы, способные отправить только простой GET, но не устраняет SSRF полностью.[7], [6] Учётные данные IAM-роли- Временные ключи AWS, выданные экземпляру. Всё, что разрешено роли, может делать и владелец ключей, пока они не истекут.[8]
Связи со стандартами
- Ссылка CWE для слабого места, описанного в этом руководстве: CWE-918
- D3-OTF Фильтрация исходящего трафика — Описанное в руководстве ограничение исходящего сетевого трафика сокращает список адресов, доступных сервису или хосту.
Хронология инцидента
Внешний исследователь сообщает об открытых данных через программу ответственного раскрытия Capital One.[2]
Capital One объявляет об инциденте, а ФБР задерживает подозреваемую в Сиэтле.[1]
Пошаговый сценарий атаки
Межсетевой экран пересылает поддельный запрос
В уголовной жалобе утверждалось, что неправильно настроенный WAF можно было заставить отправлять запросы на выбранные злоумышленником адреса, в том числе внутренние.[10]
Данные уходят массово
Скопированы данные заявок на кредитные карты с 2005 по начало 2019 года: около 100 миллионов человек в США и 6 миллионов в Канаде, в том числе около 140 000 номеров социального страхования США и 80 000 номеров привязанных банковских счетов.[2]
Исходный код: Уязвимый vs Защищённый вариант
Это иллюстративный код Flask, а не конфигурация Capital One. Список разрешённых хостов — основная прикладная мера. Обязательный прокси исходящего трафика должен проверять адрес после DNS-разрешения в момент подключения, блокировать частные и link-local диапазоны, включая сервис метаданных, и повторять эти проверки для каждого запроса и повтора; это поведение нужно подтвердить конфигурацией прокси. Перенаправления не выполняются. Отдельная проверка DNS до подключения оставила бы гонку DNS rebinding.[9], [5], [6]
import requests
from flask import Flask, request
app = Flask(__name__)
@app.get("/fetch")
def fetch():
# Сервер запрашивает любой URL, указанный вызывающей стороной.
url = request.args["target"]
resp = requests.get(url, timeout=5)
return resp.text
from urllib.parse import urlsplit
import requests
from flask import Flask, abort, request
app = Flask(__name__)
ALLOWED_HOSTS = {"images.example-cdn.com", "api.partner.example"}
EGRESS_PROXY = "http://egress-proxy.internal:3128"
# Настройте этот прокси для проверки адресата после разрешения DNS.
@app.get("/fetch")
def fetch():
parts = urlsplit(request.args.get("target", ""))
if parts.scheme != "https" or parts.hostname not in ALLOWED_HOSTS:
abort(400, "destination not allowed")
if parts.port not in (None, 443) or parts.username or parts.password:
abort(400, "destination not allowed")
resp = requests.get(parts.geturl(), timeout=(2, 5), allow_redirects=False, proxies={"https": EGRESS_PROXY}, trust_env=False)
if resp.is_redirect:
abort(502, "upstream redirect refused")
return resp.text
Чек-лист по защите системы для инженеров
- ✓Направляйте запросы URL через прокси исходящего трафика и применяйте список разрешённых хостов и политику IP-диапазонов на границе подключения: подключайтесь только к проверенному адресу и применяйте политику также при повторах. Отключите перенаправления или повторно проверяйте каждый переход; блокировки только строки 169.254.169.254 недостаточно.[9], [4]
- ✓Задайте
HttpTokens=requiredдля каждого подходящего экземпляра и проверьте уже существующие: настройки по умолчанию на уровне аккаунта не обновляют автоматически каждый экземпляр. ВыберитеHttpPutResponseHopLimitс учётом сетевого пути рабочей нагрузки; AWS предупреждает, что значение 1 может вызвать проблемы в контейнерах. Требование токена отклоняет запросы IMDSv1; hop limit — отдельная сетевая настройка, а не механизм блокировки GET без токена.[6], [7] - ✓В уголовной жалобе утверждалось, что SSRF открыл доступ к роли экземпляра. Ограничьте роль необходимыми рабочей нагрузке действиями и ресурсами, чтобы раскрытые учётные данные не давали посторонний доступ к S3.[10], [8]
- ✓Рекомендация FlawOpen по обнаружению: создавайте оповещение при использовании временных учётных данных роли вне сети экземпляра и проверяйте контекст рабочей нагрузки и облачного аудита.
- ✓На ревью кода считайте любой путь, где пользователь влияет на URL, запрашиваемый сервером, столь же опасным, как путь, где он влияет на SQL-запрос, и требуйте для него теста белого списка.[9], [5]
Источники
- Министерство юстиции США — в Сиэтле арестована IT-специалистка за кражу данных крупной финансовой компании (29 июля 2019 г.)
- Capital One — информация об инциденте кибербезопасности 2019 года
- OCC — гражданский штраф Capital One за инцидент 2019 года (август 2020 г.)
- Почему SSRF так опасен в облачных средах?
- Может ли fetch() вызвать SSRF?
- AWS — Configure the Instance Metadata Service options
- AWS — Use the Instance Metadata Service to access instance metadata
- AWS — Retrieve security credentials from instance metadata
- OWASP — Server Side Request Forgery Prevention Cheat Sheet
- DOJ — United States v. Paige Thompson, criminal complaint (29 July 2019)