Durante um teste de intrusão de rotina para uma empresa de média dimensão, a nossa equipa de segurança encontrou algo que deixou o CTO do cliente em silêncio durante cerca de dez segundos, a meio da chamada.
Tínhamos acabado de enviar um email ao diretor financeiro da empresa a partir do endereço de email do CEO. Pedia uma transferência bancária urgente para um novo fornecedor. Chegou à caixa de entrada. Sem filtro de spam, sem banner de aviso, sem nenhuma mensagem de "este email pode ser suspeito". Tinha exatamente o mesmo aspeto de qualquer outro email que o CEO alguma vez tivesse enviado.
Fizemo-lo a partir de um portátil no Porto, com um único comando e sem acesso à infraestrutura de email da empresa. Sem palavras-passe, sem contas pirateadas, sem acesso interno. Apenas um registo DNS mal configurado que estava à vista de todos há mais de três anos. Da consulta DNS ao email entregue, tudo demorou menos de dois minutos.
Eis porque funcionou e como fechar a falha.
O que encontrámos
A empresa tinha uma configuração normal: uma plataforma de caixas de correio alojada para os colaboradores, um serviço de email transacional para notificações automáticas e uma plataforma de marketing para newsletters. O DNS tinha três problemas:
- O DMARC estava em
p=none. A política existia, mas dizia aos recetores para não fazerem nada quando uma mensagem falhava. - O SPF terminava em softfail (
~all) em vez de hard fail (-all). Um servidor não autorizado recebia um veredicto de "suspeito", não uma rejeição. - O DKIM não estava configurado em todos os serviços de envio.
Ligámo-nos ao servidor de correio da empresa, encontrado através do registo MX público, na porta 25, que tem de estar aberta para o email funcionar. O servidor que recebeu a mensagem verificou o SPF e viu um softfail, verificou o DMARC e viu p=none, e entregou-a. Qualquer pessoa na internet podia ter feito o mesmo.
O registo DMARC decidiu o resultado: dos três, é o único que fala do endereço que o destinatário vê. É a falha por trás do Business Email Compromise (BEC): pagamentos a fornecedores falsos, alterações falsas de dados bancários, tudo sem nenhuma conta pirateada.
Como funciona a falsificação
Um email tem dois endereços de remetente:
- O remetente do envelope, o
MAIL FROMda conversa SMTP, guardado depois comoReturn-Path. O destinatário nunca o vê. - O cabeçalho From, o endereço que o cliente de email mostra. O SMTP não o verifica: quem envia pode escrever lá o que quiser.
Cada norma verifica uma coisa diferente:
- O SPF verifica se o servidor que se liga pode enviar pelo domínio do remetente do envelope. Nunca olha para o cabeçalho From.
- O DKIM verifica que a mensagem foi assinada com uma chave publicada sob algum domínio e que não mudou desde então. Esse domínio, o valor
d=do cabeçalhoDKIM-Signature, pode ser qualquer um. - O DMARC pergunta se um resultado SPF ou DKIM aprovado pertence ao domínio do cabeçalho From. Essa correspondência chama-se alinhamento: uma mensagem passa o DMARC se o SPF passar e o domínio do envelope estiver alinhado com o domínio do From, ou se o DKIM passar e o domínio
d=estiver alinhado com ele. A política (p=none,quarantineoureject) diz ao recetor o que fazer quando nenhuma das duas coisas acontece.
É por isso que o SPF sozinho não trava o ataque, nem com -all. Um atacante pode pôr o seu próprio domínio no envelope, com um registo SPF que passa, e o endereço do teu CEO no cabeçalho From. Só o DMARC percebe que esse aprovado pertence a outra pessoa.
As mensagens recebidas registam os veredictos no cabeçalho Authentication-Results. Uma falsificação de um domínio desprotegido:
Authentication-Results: mx.example.net;
spf=pass smtp.mailfrom=attacker.example.org;
dkim=none;
dmarc=fail header.from=example.comO SPF passou, para o domínio errado; o DMARC falhou. A entrega depende agora da política que o example.com publica.
Verifica o teu próprio domínio
Três consultas mostram o que um atacante vê (substitui example.com pelo teu domínio):
dig +short TXT example.com
dig +short TXT _dmarc.example.com
dig +short TXT s2026a._domainkey.example.comA primeira devolve todos os registos TXT do teu domínio. Exatamente uma linha deve começar por "v=spf1; duas é um erro. Uma linha com várias strings entre aspas está bem: os registos longos são divididos em strings de 255 caracteres que os recetores voltam a juntar. Depois lê o final: -all (fail), ~all (softfail), ?all (neutral) ou +all (pass para qualquer um).
A segunda devolve o teu registo DMARC, por exemplo "v=DMARC1; p=none". Sem resposta, não há DMARC: cada recetor aplica o seu próprio critério e ninguém te envia relatórios. Duas respostas v=DMARC1 significam que os recetores não aplicam nenhuma política DMARC. Tudo o que fique aquém de p=reject, ou de quarantine como passo intermédio, deixa a porta aberta.
A terceira precisa de um seletor, e o DNS não permite listá-los. Tira-o de uma mensagem real: no cabeçalho DKIM-Signature, s=s2026a; d=example.com significa que a chave está em s2026a._domainkey.example.com. Repete para cada sistema que envia pelo teu domínio. A resposta deve conter v=DKIM1 e um valor p= longo; se for um CNAME para o teu fornecedor, aparece primeiro o destino. Um p= vazio indica uma chave revogada.
O difícil é saber que sistemas devem constar destes registos. Pede uma avaliação gratuita de email spoofing e a nossa equipa de segurança analisa os teus registos SPF, DKIM e DMARC, conta as tuas consultas SPF, lista todos os serviços que enviam pelo teu domínio e diz-te se hoje alguém o pode falsificar.
SPF: onde falha sem dar sinal
Um registo SPF correto enumera todos os sistemas autorizados a enviar pelo teu domínio e, no fim, um veredicto para tudo o resto:
example.com. IN TXT "v=spf1 include:_spf.mail.example.net include:spf.crm.example.org ip4:203.0.113.25 -all"Quatro erros explicam a maioria dos SPF avariados:
- Dois registos SPF no mesmo nome. Acrescentar um remetente com um segundo registo
v=spf1em vez de editar o primeiro faz o SPF devolverpermerror. Junta-os. +allou?all. O primeiro autoriza a internet inteira. O segundo não afirma nada.- O limite de 10 consultas.
include,a,mx,ptr,existseredirectcontam cada um como uma consulta, incluindo os que estão dentro dos registos que incluis;ip4,ip6eallnão contam. Com mais de 10, o resultado épermerror. - Remetentes esquecidos. Faturação, CRM, ticketing, o scanner que envia PDF por email, os alertas de monitorização, o formulário de contacto do site. No WordPress esse formulário costuma funcionar através de um plugin, que também faz parte da superfície de ataque do site.
Para contar, corre dig +short TXT sobre o destino de cada include. Imagina que o teu registo tem três includes e um mx: quatro consultas. Se o include da plataforma de caixas de correio tiver mais três, já vais em sete. Perto do limite, remove os remetentes que já não usas, passa os envios em massa para um subdomínio com registo próprio ou substitui a e mx pelos teus próprios intervalos ip4. Nunca coles os IP de um fornecedor no teu registo: mudam sem aviso.
Quando o DMARC já aplica a política, tanto ~all como -all são defensáveis. Alguns recetores atuam perante um hard fail de SPF antes de avaliarem o DMARC e rejeitam email reencaminhado que o DKIM teria salvado, por isso algumas equipas mantêm ~all. O que falha é ~all sem uma política DMARC aplicada, exatamente o estado que encontrámos.
Muitos remetentes alojados também põem o seu próprio domínio de devolução no envelope, por isso o SPF passa para eles e não fica alinhado. Um domínio de devolução personalizado sob o teu resolve isso; o DKIM com o teu domínio é mais robusto.
DKIM: um seletor por remetente
O DKIM costuma sobreviver a um reencaminhamento simples e o SPF não, por isso é a via de alinhamento em que te deves apoiar:
- Um seletor por sistema de envio. A plataforma de caixas de correio assina com
s2026a, o CRM comcrm2026. Os sistemas nunca partilham uma chave, e dispensar um fornecedor significa apagar um registo. - Assina como o teu domínio. Muitas plataformas assinam com o seu próprio domínio até configurares a assinatura com domínio personalizado. Essa assinatura passa mas não alinha: o
d=deve serexample.comou um dos seus subdomínios. - Chaves RSA de 2048 bits. A norma DKIM exige pelo menos 1024 bits e recomenda 2048.
Para verificar o tamanho de uma chave publicada:
dig +short TXT s2026a._domainkey.example.com | tr -d '" \n' | sed -n 's/.*;p=\([^;]*\).*/\1/p' | openssl base64 -d -A | openssl pkey -pubin -inform DER -noout -text | head -1Procura Public-Key: (2048 bit) no resultado.
Roda as chaves com uma periodicidade que consigas cumprir, por exemplo duas vezes por ano, e de imediato se uma chave puder ter sido exposta:
- 1Publica uma chave nova com um seletor novo (
s2026b). - 2Depois de expirar o TTL do DNS, muda a assinatura para esse seletor.
- 3Mantém o registo antigo durante cerca de uma semana, para que o email atrasado continue a ser verificado, e depois revoga-o com um
p=vazio ou apaga-o.
DMARC: de p=none a p=reject sem perder email
O p=none foi pensado para ser temporário: mostra-te quem envia pelo teu domínio antes de pedires aos recetores que bloqueiem alguém. Se ficar assim, reporta o ataque e entrega-o.
Fase 1: monitorizar
_dmarc.example.com. IN TXT "v=DMARC1; p=none; rua=mailto:dmarc-reports@example.com"Os recetores que suportam relatórios enviam relatórios agregados para o endereço rua, normalmente uma vez por dia, em XML comprimido. Uma caixa de correio noutro domínio tem de ser autorizada lá com um registo TXT "v=DMARC1" em example.com._report._dmarc.reports.example.net, ou não chega nenhum relatório.
Fase 2: ler os relatórios
Cada registo mostra quantas mensagens um IP de origem enviou com o teu domínio no From, e como correram:
<record>
<row>
<source_ip>198.51.100.42</source_ip>
<count>318</count>
<policy_evaluated>
<disposition>none</disposition>
<dkim>fail</dkim>
<spf>fail</spf>
</policy_evaluated>
</row>
<identifiers>
<header_from>example.com</header_from>
</identifiers>
<auth_results>
<dkim>
<domain>crm.example.org</domain>
<result>pass</result>
</dkim>
<spf>
<domain>bounce.crm.example.org</domain>
<result>pass</result>
</spf>
</auth_results>
</record>É um remetente legítimo a falhar o DMARC: o CRM assina e trata as devoluções com o seu próprio domínio, por isso as duas verificações passam e nenhuma alinha. Classifica cada origem num de quatro grupos:
- Teus e alinhados: feito.
- Teus e a falhar: a tua lista de trabalho. Corrige cada um com DKIM com o teu domínio ou com um domínio de devolução personalizado.
- Reencaminhadores e listas de correio: o SPF quebra ao reencaminhar; o DKIM sobrevive a menos que a mensagem seja alterada, como as listas costumam fazer. Não te cabe a ti corrigi-los.
- Desconhecidos: consulta o IP (
dig +short -x 198.51.100.42). É um remetente de que ninguém te falou ou alguém a fazer-se passar por ti; descobre qual antes de aplicares a política.
Um parser open source como o parsedmarc torna o XML pesquisável. Fica nesta fase até a lista de trabalho estar vazia durante um mês inteiro, para que a faturação de fim de mês apareça.
Fase 3: quarentena, de forma gradual
_dmarc.example.com. IN TXT "v=DMARC1; p=quarantine; pct=25; rua=mailto:dmarc-reports@example.com"pct=25 põe em quarentena um quarto das mensagens que falham; as restantes recebem a política imediatamente mais fraca, aqui none. Sobe para 50 e depois para 100 (o valor por defeito), lendo os relatórios em cada passo.
Fase 4: rejeitar
_dmarc.example.com. IN TXT "v=DMARC1; p=reject; sp=reject; rua=mailto:dmarc-reports@example.com"Duas tags merecem uma decisão:
sp=define a política para os subdomínios sem registo DMARC próprio; se a omitires, herdam op=. Uma falsificação a partir debilling.example.com, um nome que nunca enviou email, não tem SPF nem DKIM para passar, por isso é a política de subdomínio que a trava. Umsp=rejectexplícito mantém-se enquanto ajustas op=.adkim=easpf=definem o alinhamento. Ambos são relaxados por defeito (r):mail.example.comalinha comexample.com. O estrito (s) exige correspondência exata; escolhe-o só quando todos os remetentes usam exatamente o teu domínio.
Domínios que não enviam email
Domínios estacionados, domínios com erros ortográficos registados por defesa e domínios de marcas antigas que só redirecionam o site são fáceis de falsificar porque ninguém olha para eles. Declara que não enviam nem recebem nada:
example.org. IN MX 0 .
example.org. IN TXT "v=spf1 -all"
_dmarc.example.org. IN TXT "v=DMARC1; p=reject; sp=reject; adkim=s; aspf=s; rua=mailto:dmarc-reports@example.com"
example.org._report._dmarc.example.com. IN TXT "v=DMARC1"O null MX (RFC 7505) diz que o domínio não aceita email, por isso os remetentes falham de imediato em vez de tentarem de novo. O SPF não autoriza nenhum servidor, o DMARC rejeita tudo o que alegue vir do domínio ou dos seus subdomínios, e a última linha, na tua zona principal, deixa os relatórios chegarem à tua caixa de correio.
Depois de p=reject: continua a vigiar
As configurações de email vão-se desviando com o tempo:
- Mantém o
ruapara sempre. Revê os relatórios todas as semanas; cria alertas para uma origem nova a falhar em volume ou para um remetente legítimo cuja taxa de aprovação desce. - Controla os novos remetentes. Antes de uma ferramenta nova enviar pelo teu domínio: DKIM com o teu domínio, consultas SPF recontadas e uma mensagem de teste que mostre
dmarc=pass. - Remove os remetentes que saem. Apaga o include e o seletor quando o contrato termina.
- Controla as alterações ao DNS. Um segundo registo SPF costuma vir de uma edição apressada no painel do registrar. Se geres os teus próprios servidores BIND 9, o DNS Manager, a interface web open source da Privum para BIND 9, sujeita as alterações de registos a controlo de acesso por perfis e a um registo de auditoria.
- Verifica a partir de fora. Corre isto a partir do cron ou do CI contra todos os teus domínios.
#!/usr/bin/env bash
# Usage: check-mail-auth.sh example.com (exits 1 on failure)
set -eu
d="$1"
dmarc=$(dig +short TXT "_dmarc.$d")
dmarc_n=$(echo "$dmarc" | grep -ci '^"v=DMARC1' || true)
spf=$(dig +short TXT "$d" | grep -ci '^"v=spf1' || true)
[ "$dmarc_n" -eq 1 ] || { echo "FAIL $d: $dmarc_n DMARC records, expected 1"; exit 1; }
echo "$dmarc" | grep -Eq ';[[:space:]]*p=reject' || { echo "FAIL $d: DMARC is not at p=reject"; exit 1; }
[ "$spf" -eq 1 ] || { echo "FAIL $d: $spf SPF records, expected 1"; exit 1; }
echo "OK $d"Os registos podem parecer certos e ainda assim deixar uma falha, como um subdomínio com o seu próprio registo DMARC permissivo. A prova é uma tentativa de falsificação contra o teu próprio servidor de correio: foi assim que encontrámos esta, durante um teste de intrusão.
Descobre se o teu domínio pode ser falsificado antes que outro o descubra. Marca uma avaliação gratuita de email spoofing: verificamos o SPF, o DKIM e o DMARC em todos os teus domínios, incluindo os estacionados, identificamos cada serviço que envia em teu nome e entregamos-te um plano faseado até p=reject que mantém as faturas e as newsletters a circular.