flawopen.com/Incidents/capital-one-ssrf-imds-july-2019
SSRF na Capital One: roubo de credenciais AWS IMDSv1
A denúncia federal alegou que um WAF mal configurado permitiu SSRF até o IMDSv1 da AWS e expôs credenciais temporárias do papel e dados S3 de cerca de 106 milhões. Exija tokens e limite papéis.[10], [2]
A denúncia criminal do DOJ descreve uma cadeia como esta: Imagine uma recepcionista que busca documentos nos endereços que você informa. Um serviço de encaminhamento pode permitir que alguém direcione essa recepcionista a uma sala interna. Lá, ela pode obter um crachá temporário da carga de trabalho; o crachá só abre as salas permitidas pelo papel associado à carga. O erro foi presumir que apenas funcionários chegariam à sala, embora a recepcionista pudesse ser direcionada até lá.[10], [8]
Conceitos Centrais e Termos
SSRF- Server-side request forgery (
CWE-918): fazer um servidor enviar uma requisição escolhida pelo atacante, de modo que ela carregue a posição de rede e a confiança do servidor.[9] Web application firewall- Um filtro diante de uma aplicação web. A denúncia criminal alegou que o WAF mal configurado da Capital One podia encaminhar requisições a endereços internos.[10]
IMDSv1- Quando o IMDSv1 está habilitado, as requisições de metadados não exigem token. O caminho de credenciais de segurança do papel IAM devolve credenciais temporárias associadas a esse papel.[7], [8]
IMDSv2- O IMDSv2 usa um token de sessão obtido com uma requisição PUT. Defina
HttpTokens=requiredpara rejeitar requisições IMDSv1 sem token; isso bloqueia muitos repasses SSRF que só conseguem enviar um GET simples, mas não elimina todo o risco de SSRF.[7], [6] Credenciais de papel IAM- Chaves temporárias da AWS emitidas para uma instância. Tudo o que o papel pode fazer, quem tiver as chaves também pode, até elas expirarem.[8]
Mapeamentos de frameworks
- Referência CWE para a fraqueza descrita neste guia: CWE-918
- D3-OTF Filtragem de tráfego de saída — A restrição de rede de saída deste guia limita os destinos que o serviço ou host pode alcançar.
Linha do Tempo do Incidente
Um pesquisador externo relata os dados expostos pelo programa de divulgação responsável da Capital One.[2]
A Capital One anuncia o incidente e o FBI prende uma suspeita em Seattle.[1]
Fluxo de Ataque Passo a Paso
O firewall repassa uma requisição forjada
A denúncia criminal alega que o WAF mal configurado podia ser induzido a enviar requisições para endereços escolhidos pelo atacante, inclusive internos.[10]
Os dados saem em massa
Foram copiados dados de pedidos de cartão de crédito de 2005 ao início de 2019: cerca de 100 milhões de pessoas nos EUA e 6 milhões no Canadá, incluindo uns 140 mil números de Seguro Social americanos e 80 mil números de contas bancárias vinculadas.[2]
Código-Fonte: Vulnerável vs. Seguro
Código Flask ilustrativo, não é a configuração da Capital One. A allowlist de hosts é o controle principal da aplicação. O proxy de saída obrigatório deve aplicar a política ao endereço resolvido no momento da conexão, bloquear faixas privadas e link-local, inclusive o serviço de metadados, e repetir os controles em cada requisição e nova tentativa; verifique esse comportamento na configuração do proxy. Redirecionamentos não são seguidos. Uma verificação separada de resolução antes da conexão deixaria uma condição de corrida de DNS rebinding.[9], [5], [6]
import requests
from flask import Flask, request
app = Flask(__name__)
@app.get("/fetch")
def fetch():
# O servidor busca qualquer URL fornecida pelo chamador.
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"
# Configure este proxy para aplicar a política de destino após a resolução 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
Lista de Verificação de Segurança para Engenharia
- ✓Encaminhe buscas de URL por um proxy de saída e aplique a allowlist de hosts e a política de faixas IP no limite da conexão: conecte-se somente ao endereço verificado e aplique a política também às novas tentativas. Desative redirecionamentos ou revalide cada etapa; bloquear apenas o texto 169.254.169.254 não basta.[9], [4]
- ✓Defina
HttpTokens=requiredem cada instância aplicável e verifique as instâncias existentes, pois padrões da conta não atualizam automaticamente cada instância. EscolhaHttpPutResponseHopLimitconforme o caminho de rede da carga de trabalho; a AWS alerta que o valor 1 pode causar problemas em contêineres. A exigência de token rejeita requisições IMDSv1; o limite de saltos é uma configuração de rede separada, não o controle que bloqueia um GET sem token.[6], [7] - ✓A denúncia criminal alega que o caminho SSRF expôs o papel da instância. Limite esse papel às ações e aos recursos necessários à carga de trabalho para que a exposição de credenciais não conceda acesso S3 sem relação com ela.[10], [8]
- ✓Orientação de detecção da FlawOpen: gere alerta quando credenciais temporárias do papel forem usadas fora da rede da instância; investigue com o contexto da carga de trabalho e da auditoria em nuvem.
- ✓Na revisão de código, trate qualquer caminho em que o usuário influencie uma URL buscada pelo servidor como um em que ele influencie uma consulta SQL, e exija um teste de allowlist para ele.[9], [5]
Fontes
- Departamento de Justiça dos EUA — funcionária de tecnologia de Seattle presa por roubo de dados de grande empresa de serviços financeiros (29 de julho de 2019)
- Capital One — informações sobre o incidente de cibersegurança de 2019
- OCC — multa civil à Capital One pelo incidente de 2019 (agosto de 2020)
- Por que o SSRF é tão perigoso em ambientes de nuvem?
- fetch() pode causar 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)