SPF 邮件伪造漏洞:检测方法与实战复现

邮件伪造不需要密码,也不需要入侵邮箱。攻击者只需要找到一个 SPF 和 DMARC 配置不当的域名,就能在任意服务器上伪造该域名的发件人。本文前半部分给出一套可复用的检测方法,后半部分以 hilang.art 为例走完从伪造到修复的完整流程。

一、邮件伪造原理

SMTP 在设计中分离了两个发件人地址,而这两个地址都由发送方自行声明:

1
2
MAIL FROM:<admin@example.com>    ← 信封发件人,SMTP 传输使用
From: admin@example.com ← 头部发件人,用户可见

关键在于:SMTP 不会要求发送方证明自己拥有该域名。攻击者只需在自己的服务器上把两个地址都填成目标域名,邮件就能发出去。MX 记录只是告诉别人”收件应该往哪送”,它管不了发件端。

邮件防伪依赖三项 DNS 配置,缺一不可:

记录 作用 欠缺时的后果
SPF 声明哪些 IP/服务器有权代表域名发信 收件方无法判断发信来源是否合法
DKIM 为正常邮件添加域名私钥签名 收件方无法验证邮件内容是否被篡改
DMARC 根据 SPF/DKIM 结果决定如何处理未通过验证的邮件 即使 SPF/DKIM 发现异常,收件方也不知道该怎么处理

收件方判定 DMARC 通过的条件(满足其一即可):

1
2
3
SPF 验证通过 且 验证域与 From 头部域名一致
或
DKIM 验证通过 且 签名域与 From 头部域名一致

两项都不满足时,DMARC 验证失败,收件方按域名所有者预设的策略行事:

DMARC 策略 含义
未配置 没有任何指示,收件方自行判断
p=none 仅监控,不提出拦截要求
p=quarantine 建议放入垃圾箱或隔离区
p=reject 建议直接拒绝

一句话总结:SPF 和 DKIM 负责验证,DMARC 负责处置。三者缺其一,伪造就有可乘之机。

二、检测方法

以下给出一套完整的检测流程。这套方法不依赖任何特定工具,核心思路适用于任何邮件伪造测试场景。

2.1 信息收集

攻击者的入口永远是公开 DNS。不需要登录任何后台,三条命令即可完成信息收集。

第一步:查 MX,确认域名是否有邮件业务。

1
nslookup -type=mx example.com

MX 记录告诉你这个域名是否接收邮件、由谁接收。无论 MX 指向的是企业邮箱(腾讯、阿里、Google、Microsoft 等)、自建邮件服务器,还是虚拟主机自带的邮局,只要存在 MX 记录,就说明域名背后有真实的邮件用户,伪造发件人就有实际攻击面。

MX 为空也不意味着毫无价值——部分域名虽不接收邮件,但配置了 SPF 用于对外发信(如通知系统、营销平台),伪造这类域名的发件人仍然可能绕过某些收件方的检查。只是此时缺少收件用户作为直接攻击目标,利用链会更长。

第二步:查 SPF,确认发信来源是否受限。

1
nslookup -type=txt example.com

在返回的 TXT 记录中查找以 v=spf1 开头的内容。如果找不到,说明没有配置 SPF。

Windows 下 nslookup 可能出现 unknown type 41 之类的提示,忽略即可——判断 SPF 是否存在,只看有没有 v=spf1 开头的 TXT 记录。

SPF 记录中每个机制的含义:

机制 含义 风险提示
+all 所有服务器都视为合法发信来源 严重错误,等于没配
?all 不表态 形同虚设
~all 非授权来源为”可疑”(softfail) 有一定限制,但处置权完全交给收件方
-all 非授权来源一律拒绝(hardfail) 限制最严格

如果记录中包含 redirect= 或多个 include:,需要递归展开才能看到完整授权范围。部分 SPF 记录因格式错误或超过 10 次 DNS 查询限制而失效,这本身也是一个可利用的信号。

第三步:查 DMARC,确认处置策略。

1
nslookup -type=txt _dmarc.example.com

在返回内容中查找 v=DMARC1。常见结果及含义:

查询结果 含义
记录不存在(NXDOMAIN 或空结果) 未配置 DMARC
p=none 仅监控,不拦截
p=quarantine 要求拦截到垃圾箱
p=reject 要求直接拒绝
p=reject; sp=reject 主域和子域均要求拒绝
pct=50 仅对 50% 的邮件执行策略(可能被利用)

另外注意两个容易被忽略的字段:

  • rua= — 聚合报告接收地址,可用于确认域名是否已有监控
  • sp= — 子域策略,未设置时默认继承 p= 的值

第四步(补充):查 DKIM,判断是否有签名机制。

DKIM 没有固定查询路径,需要知道选择器(selector)。如果已通过其他方式获取到选择器名称:

1
nslookup -type=txt <selector>._domainkey.example.com

如果无法获取选择器,可先默认 DKIM 未配置——绝大多数未做邮件安全加固的域名不会主动配置 DKIM。

2.2 配置风险判定

收集完信息后,按下表判定风险等级:

SPF 状态 DMARC 状态 风险等级 说明
未配置 未配置或 p=none 高 完全没有任何防护,优先验证
+all 任意 高 SPF 授权所有服务器,等同于没有限制
?all 未配置或 p=none 高 SPF 不表态 + DMARC 不处置 = 无防护
~all 未配置或 p=none 中高 SPF 仅标记可疑,但无 DMARC 指示处置方式
格式错误/多条/解析失败 未配置或 p=none 中 SPF 可能被绕过或忽略
-all 未配置或 p=none 中低 SPF 限制严格但缺少 DMARC 强制处置
-all p=quarantine 低 伪造邮件大概率被隔离
-all p=reject 极低 伪造邮件大概率被拒绝

重要区分:以上判定仅基于 DNS 信息,属于”配置风险”评估。不能将”配置存在缺陷”直接等同于”漏洞可被利用”。最终结论必须通过实际发信测试来确认。

2.3 发信验证

DNS 风险只是线索,必须通过实际发信来验证。验证逻辑是:在不受目标域名 SPF 授权的服务器上,伪造该域名的发件人地址,向测试邮箱发送邮件,观察收件方的处理结果。

测试环境要求:

  • 一台不受目标域名 SPF 授权的服务器(VPS、云主机或本地 Kali 均可)
  • 一个用于接收测试邮件的邮箱(建议用主流免费邮箱,如 QQ、Gmail、Outlook)
  • 确保测试服务器的 25 端口未被 ISP 封锁

Swaks 基础用法:

1
2
3
4
5
6
7
8
9
10
# 先查收件方 MX
nslookup -type=mx qq.com

# 用 Swaks 发信
swaks --server <收件方MX>:25 \
--to <你的测试邮箱> \
--from admin@<目标域名> \
--header "From: admin@<目标域名>" \
--header "Subject: SPF spoofing test - <目标域名>" \
--body "This is a security testing email."

命令拆解:

  • --server:直连收件方 MX,不经过目标域名的发信服务器
  • --from:设置信封发件人(MAIL FROM),填目标域名的地址
  • --header "From:":设置头部发件人,同样填目标域名的地址
  • 全程不需要任何账号密码

2.4 结果判定

发信后的 SMTP 返回码和邮件最终去向,共同决定漏洞是否成立。判定分两步——先看 SMTP 会话结果,再看邮件最终投递位置。

第一步:SMTP 会话阶段判定。

发信后立刻观察 Swaks 输出的 SMTP 返回码:

SMTP 返回 含义 下一步
250 OK 且 queued as 收件服务器接受了邮件,进入后续处理队列 进入第二步,检查邮件实际去向
550 系列(如 550 DMARC check failed) 收件服务器在 SMTP 阶段直接拒绝 伪造未完成投递,漏洞不成立
450/451 系列 临时拒绝(灰名单、频率限制等) 等待后重试,或更换发信 IP
550 Sender rejected / 553 发件人被拒(可能是 IP 信誉问题) 排除 IP 信誉干扰后重新测试

第二步:邮件投递位置判定。

如果 SMTP 返回了 250,去测试邮箱确认邮件的最终位置:

实际去向 判定 漏洞严重程度
邮件始终未收到 可能在后续处理中被静默丢弃 无法直接利用
进入垃圾箱/隔离区 发件人伪造成立,收件方已采取限制措施 低危(可发信但被标记)
进入正常收件箱,无警告标识 伪造邮件被当作正常邮件投递 高危(可直接用于钓鱼攻击)
进入正常收件箱,有”未验证”等提示 邮件投递成功但收件方有提示 中危(仍可用于攻击但可能引起警觉)

三步验证总结:

1
2
3
4
5
6
7
8
9
10
DNS 信息收集
↓
配置风险"高"?→ 有继续验证的价值
↓
未授权发信且 SMTP 返回 250?
↓ 是
邮件最终去了哪里?
├── 正常收件箱、无警告 → 高危,可被直接利用
├── 垃圾箱/隔离区 → 低危,伪造成立但已被限制
└── 未收到 → 被静默拦截,暂时无法利用

这套方法的核心逻辑是:DNS 告诉你”可能有问题”,SMTP 返回告诉你”能不能发”,邮件最终位置告诉你”问题有多大”。三个维度缺一不可。

三、实战复现

以下以 hilang.art 为例,逐步演示上述检测方法的完整应用。

3.1 信息收集

hilang.art 使用腾讯企业邮箱,MX 记录如下:

1
nslookup -type=mx hilang.art
1
2
hilang.art  MX preference = 5,  mail exchanger = mxbiz1.qq.com
hilang.art MX preference = 10, mail exchanger = mxbiz2.qq.com

域名确实在使用企业邮箱。接下来查 SPF:

1
2
3
nslookup -type=txt hilang.art
nslookup -type=txt hilang.art 1.1.1.1
nslookup -type=txt hilang.art 223.5.5.5

三个来源均未返回 v=spf1 开头的 TXT 记录。再查 DMARC:

1
nslookup -type=txt _dmarc.hilang.art 1.1.1.1

同样不存在。DKIM 选择器未知,默认视为未配置。

信息收集结论:

1
2
3
4
5
MX     → 已指向腾讯企业邮箱(域名有邮件业务)
SPF → 未配置
DKIM → 未配置
DMARC → 未配置
风险等级 → 高(完全无防护)

按照 2.2 的判定标准,这是一个完全无防护的域名,值得进入发信验证阶段。

3.2 发信验证

查 QQ 邮箱 MX:

1
nslookup -type=mx qq.com

优先级最高的为 mx3.qq.com。在 Kali 上执行 Swaks(收件地址已脱敏):

1
2
3
4
5
6
swaks --server mx3.qq.com:25 \
--to YOUR_QQ@qq.com \
--from admin@hilang.art \
--header "From: admin@hilang.art" \
--header "Subject: hilang.art SPF test" \
--body "SPF spoofing test"

SMTP 交互过程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
=== Connected to mx3.qq.com.

-> MAIL FROM:<admin@hilang.art>
<- 250 OK

-> RCPT TO:<测试QQ邮箱>
<- 250 OK

-> DATA
<- 354 End data with <CR><LF>.<CR><LF>.

-> From: admin@hilang.art
-> Subject: hilang.art SPF test
-> SPF spoofing test
-> .

<- 250 OK: queued as.

未配置邮件防伪策略时,QQ 接收伪造邮件

3.3 判定

  • SMTP 返回 250 OK,邮件被接受
  • 去 QQ 邮箱检查:在垃圾箱中找到了这封邮件,发件人显示为 admin@hilang.art

按照 2.4 的判定标准:

发件人伪造成立(SMTP 返回 250、邮件进入垃圾箱),但收件方(QQ)已采取限制措施,未进入正常收件箱。判定为低危——可伪造发件人,但无法绕过 QQ 的垃圾邮件过滤。

四、为什么邮件进了垃圾箱

很多测试者会在这一步困惑:既然 SPF、DKIM、DMARC 全都没配,为什么邮件没有直接进入收件箱?

原因在于:域名没有配置防伪策略,不代表收件服务器不做任何判断。QQ 在处理这封邮件时经历了以下逻辑:

1
2
3
4
5
6
7
8
9
10
11
发信服务器 IP 不在 hilang.art 的 SPF 白名单中(因为没有 SPF 可供核对)
↓
邮件没有 hilang.art 的 DKIM 签名(因为没有配置 DKIM)
↓
没有 DMARC 记录告诉 QQ 怎么处理(因为没有配置 DMARC)
↓
QQ 无法从域名配置中判断合法性,转而使用自身反垃圾策略
↓
根据发信 IP 信誉、邮件内容、发信行为等维度综合打分
↓
判定为可疑 → 放入垃圾箱

这里的关键认知是:**SPF/DKIM/DMARC 是域名所有者向收件方提供的判断依据。没有这些依据时,收件方不会”放行”,而是用自己的规则来判断。**只是这些规则不一定可靠——当发信 IP 信誉够好、邮件内容够正常时,没有防护的域名伪造邮件完全可能进入正常收件箱。

仅配置 SPF 和 DKIM 而不配 DMARC 也是同样的道理:SPF 能告诉 QQ”这台服务器不是合法来源”,DKIM 能告诉 QQ”这封邮件没有有效签名”,但如果没有 DMARC,QQ 就只能自行决定如何处理这些异常信号。

五、修复与对比验证

复现完成后,为 hilang.art 逐步添加防护并验证效果。

5.1 配置 SPF

在 DNSPod 添加腾讯企业邮箱推荐的 SPF 记录:

1
2
3
4
主机记录:@
记录类型:TXT
记录值:v=spf1 include:spf.mail.qq.com ~all
TTL:600

验证生效:

1
nslookup -type=txt hilang.art 223.5.5.5
1
hilang.art  text = "v=spf1 include:spf.mail.qq.com ~all"

5.2 配置 DKIM

在企业微信后台启用 DKIM:

1
协作 → 邮件 → 设置 → DKIM 验证 → 配置

后台生成的选择器为 luya2607._domainkey,将提供的 DKIM 公钥作为 TXT 记录添加到 DNSPod 后,回到企业微信完成验证。

5.3 配置 DMARC

1
2
3
4
主机记录:_dmarc
记录类型:TXT
记录值:v=DMARC1; p=reject
TTL:600

多源确认:

1
nslookup -type=txt _dmarc.hilang.art 223.5.5.5
1
_dmarc.hilang.art  text = "v=DMARC1; p=reject"

5.4 再次验证

SPF、DKIM、DMARC 全部生效后,重新运行相同的 Swaks 命令:

1
2
3
4
5
6
7
8
9
 -> MAIL FROM:<admin@hilang.art>
<- 250 OK ← MAIL FROM 阶段仍被接受

-> RCPT TO:<测试QQ邮箱>
<- 250 OK ← RCPT TO 阶段也通过

...提交完整邮件后...

<** 550 DMARC check failed [IP: 测试机公网IP].

配置 DMARC 拒绝策略后,QQ 返回 550 并拒绝伪造邮件

DMARC 的处理逻辑在此时体现得非常清楚:SPF 检查发现发信 IP 不在腾讯的授权范围内,DKIM 检查发现邮件没有企业微信私钥签发的签名,两项都通不过,DMARC 根据 p=reject 要求 QQ 拒绝投递——QQ 照做了。

两轮测试对比:

阶段 SPF DKIM DMARC SMTP 返回 最终结果
修复前 无 无 无 250 OK: queued as. 进入垃圾箱
修复后 include:spf.mail.qq.com ~all 已配置 p=reject 550 DMARC check failed SMTP 阶段拒绝
上一篇
下一篇