邮件伪造组合拳

 

作者:Imanfeng

0x00 前言

此前进行邮件伪造,主要使用近似域名或者使用Smtp2go来进行发信绕过。上个月发现一个邮件伪造工具 espoofer,通过对工具和相关Paper的学习本文将以涉及的相关技巧展开。

由于某项目的开始月初搁置了文章整理,近日发出来与大家分享学习。

 

0x01 邮件传输

SMTP协议是基于TCP协议,也要进行三次握手

  1. 建立连接
  2. 传输数据
  3. 断开连接


在邮件传输过程中会提到的两个From:

① MAIL FROM:在SMTP认证中代表是谁发的,后面统称Smtp.From;
② Message FROM:定义在邮件内容Header中,呈现给收件人的From字段,在后面统称Message.From

一个完整的发信简图如下,可以发现在原生SMTP整个过程中并没有任何身份校验的机制,HELO/MAIL FROM(Smtp.From) 以及From(Message.From)均是可控可定义的。

 

0x02 邮服防护

SPF

主要作用是校验发信服务器IP地址,防止发件人欺骗


假设b.com邮件服务器收到了一封邮件,发送主机的 IP 是1.2.3.4,并且声称自己的Smtp.From字段为s@a.com。为了确认发件人不是伪造的,邮件服务器b.com会去查询a.com的 SPF 记录。如果该域不存在SPF即随便伪造;如果存在 SPF 记录并且设置允许 IP 为1.2.3.4的主机发送邮件,则服务器就认为这封邮件是合法的,如果 IP 不在允许范围内,则大多数情况会显示为代发标识

 

DKIM

主要作用是校验邮件标头签名信息,防止邮件内容篡改

在a.com的DNS上设置DKIM公钥,假设通过a.com发送邮件,邮件服务器使用提前配置的私钥加密邮件相对应内容,生成DKIM-Signature签名及相关信息插入到邮件标头中;当b.com邮件服务器收到了邮件时,通过DNS查询获得此前配置的对应公钥,验证邮件DKIM签名的有效性,从而确认在邮件发送的过程中邮件是否篡改
DKIM签名结构如下所示:

  DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
      d=anxus.top; l=1850; s=selector; t=1452769712;
      h=date:from:from:to:message-id:subject:mime-version;
      bh=yCbsFBJJ9k2VYBxKGgyNILalBP3Yzn1N8cMPQr92+zw=;
      b=bnuXrH/dSnyDR/kciZauK4HTgbcDbSFzmHR78gq+8Cdm20G56Ix169SA...

a:签名算法
c:用于对标头和正文的算法规范化,simple&relaxed
d:是这一个域的签名。在DMARC检查签名中的域是否和发送者的域相匹配中用到
q:定义用于检索DKIM公钥的查询方法。它不必存在,默认为“ dns / txt”
s:在DNS中寻找RSA密钥的参数
h:应该包含在签名中的邮件头字段列表
bh:邮件正文的hash
b:是签名本身的核心,包括’h’给出的字段,以及DKIM-Signature头本身(视b=为空)

public_key = dkim_find_key(q_val, d_val, s_val)

 

DMARC

只有SPF与DKIM其实并不能真正对邮件的发件人进行身份验证:因为SPF只能对Smtp.From进行来源IP的验证,DKIM只能保证对应内容不被篡改,但收信人真正看见的字段是定义在邮件头中的Message.From,两者无法保证该字段是真实的。

故在2015年3月发布的文档RFC 7489定义了DMARC,其中引入标识符对齐机制(Identifier Alignment):作用是确保通过SPF/DKIM校验的域名与Message.From发件人地址可以对齐匹配,从而保证最终用户看到的来源地址是真实可信的。

DMARC有两种对齐匹配机制:严格模式和宽松模式

  • 严格模式,两个域必须相同才能彼此对齐,例如SPF标识符对齐Demo:
    Smtp.From为:
    imanfeng@360.cn
    

    邮件头内容为:

    From: imanfeng@360.cn
    Date: Fri, Feb 15 2002 16:54:30 -0800
    To: jane@360.cn
    Subject: Hi!
    

    例如DKIM标识符对齐DEMO:

    d=360.cn
    

    邮件头内容为:

    From: imanfeng@360.cn
    Date: Fri, Feb 15 2002 16:54:30 -0800
    To: jane@360.cn
    Subject: Hi!
    
  • 宽松模式,两个组织域(主域名)相同时两个域即对齐,例如SPF表示符对齐Demo:
    Smtp.From为
    imanfeng@lintonlab.360.cn
    

    邮件头内容为

    From: imanfeng@360.cn
    Date: Fri, Feb 25 2019 03:14:20 -1200
    To: jane@example.org
    Subject: Hi!
    

    例如DKIM标识符对齐DEMO:

    d=lintonlab.360.cn
    

    邮件头内容为

    From: imanfeng@360.cn
    Date: Fri, Feb 25 2019 03:14:20 -1200
    To: jane@360.cn
    Subject: Hi!
    

DMARC除了进行对齐校验外,还可以配置处理的策略,如下图所示:

p:用于告知收件方,当检测到某邮件存在伪造发件人的情况,收件方要做出什么处理:reject为拒绝该邮件;none为不作任何处理;quarantine为将邮件标记为垃圾邮件
sp:规定子域的处理策略
rua:发送综合反馈的邮件地址
ruf:发送消息详细故障信息的邮件地址
dkim:要求dmarc对于dkim的对齐标准
aspf:要求dmarc对于spf的对齐标准

邮件通过DMARC检测的流程如下图所示:

1.邮件发送
2.接收方从邮件中取出字段Message.From的domain
3.使用domain字段与SPF/DKIM的上述domain经过对齐校验(默认为宽松对齐)
4.SPF/DKIM均通过校验并且其domain通过对齐校验
5.通过DMARC校验,收到邮件

 

0x03 邮件绕过

正常发收件​​​​认证流程如下:


1.Alice定义内容发送邮件
2.SPF校验发送ip是否在DNS记录ip范围【HELO&MAIL FROM】
3.DKIM查询DNS中的公钥校验邮件头签名准确性【签名校验】
4.DMARC对齐校验【domain】
5.Bob收到邮件

最核心的思想就是利用不同组件传递过程中的差异性进行绕过

Ⅰ.校验歧义性绕过

① 不存在子域差异性

关于SPF以及DMARC官方有特殊定义:

1.SMTP定义了身份标识符有HELO 和 MAILFROM(Smtp.From)
2.SPF同时检测HELO 和 MAILFROM,有一个失败即SPF校验失败
3.DMARC校验SPF时默认使用MAILFROM进行对齐,当MAILFROM为空会使用HELO进行对齐校验

利用流程(Espoofer – server_a1):

1.HELO及MAIL FROM恶意字段如上图所示;
2.MAIL FROM的域名字段是子域名并没有配置SPF,故进行SPF校验时是查询不到,但查询不到并不会被判断为SPF校验失败!与此同时HELO是可以通过SPF判断,故SPF通过;
3.DMARC优先使用Smtp.From的domain与Message.From的domain进行对齐,此时是可以通过宽松模式对齐的,故DMARC通过(没有强制要求严格模式对齐的情况下)。

这种绕过情况下由于Smtp.From与Message.From不一致,部分邮件接收方会进行一个代发提示,如下图所示:


此时可利用场景为,将子域名定义为mail、office等进行官方发件的伪装,前提是子域不存在SPF记录。apple.com的子域一直可以解析到spf记录,故此方法是无法绕过的

 

② MAIL FROM置空差异性

该利用点在于不同校验组件对”空”的Smtp.From字段处理方式不同(Espoofer – server_a2):


1.部分SPF组件会将“(any@legitimate.com”视为空的Smtp.From,那么就会转向对HELO进行SPF校验并且顺利通过;
2.到后面DMARC组件并不认为它是空地址,故会继续使用Smtp.From=legitimate.com与Message.From=legitimate.com进行对齐校验,故存在绕过SPF&DMARC的可能。

 

③ 解析截断差异性

该利用点在于不同校验组件会存在解析截断,从而造成差异性绕过:

利用流程(Espoofer – server_a3):

1.攻击者在attack.com解析中添加公钥,构造DKIM头通过私钥加密需要加密的信息进行发送;
2.邮件服务器原本公钥构造应该为attack.com.\x00.any._domainkey.bank.com(s+[._domainkey.]+d);
3.由于部分语言如C在解析过程中会存在\x00截断,导致接收方服务器处理后获取公钥的地址直接为attack.com,该内容可控故存在绕过。

 

Ⅱ.认证头内容注入

这个绕过技巧主要在于SPF和DKIM组件如何将它们验证的结果信息传递给DMARC来进行对齐检查,思路的话就是想如何在通过DMARC的情况下让SPF/DKIM去验证我们可控的域名内容

 

① DKIM 认证头内容注入

1.如上图所示为攻击者发送的恶意邮件头内容,当DKIM校验内容时,拼接公钥内容地址为selector._domainkey.legitimate.com(. attacker.com ,由于在attacker.com上读取故可控,从而可通过DKIM验证;

2.DKIM组件会生成验证头发送给DMARC进行对齐:

   Authentication-results:victim.com;dkim=pass
   (1024-bitkey)header.d=legitimate.com(.attacker.com

3.DMARC收到验证头内容后,会将(后面的内容作为注释,故将Message.From的legitimate.com与d=legitimate.com进行对齐匹配测试,从而通过校验。

“(”, double (“) and single (’)均可作为注释。

 

② SPF 认证头内容注入

方案一(Espoofer – server_a5)

如图所示为:

1.当SPF校验内容时,Smtp.From的domain为legitimate.com(.attacker.com ,SPF去校验了legitimate.com(.attacker.com的SPF,内容可控故顺利通过SPF校验;
2.当进行DMARC校验时,同样会将(后视为注释,将Message.From的legitimate.com与Smtp.From的legitimate.com进行对齐匹配,从而通过DMARC匹配。

方案二(Espoofer – server_a6)

某些邮件服务器进行地址校验不允许方案一的地址格式,可换种格式如上图样例所示:

1.邮件服务器收到邮件会以第二个@作为分隔,故判断为合法邮件;
2.此时当SPF组件选择第一个@作为分隔所选的校验domain即为legitimate.com'@a.attack.com,从而通过SPF校验;
3.当进行DMARC校验通过注释过后仍然可以通过对齐匹配。

 

Ⅲ.UI相关差异绕过

我们把邮件接收处理的过程大致可以分为两个阶段

1.从MIME原始报文提取至Message.Header
2.从Message.Header提取出响应的domain以及email-address

故存在一种场景:邮件服务器和客户端所展示的信息经过不同的处理传递过程中可能会产生差异,从而在传递过程中造成绕过利用

 

① 邮件头不一致性

多个发件人地址进行绕过

根据RFC 5322表示一个邮件消息必须有一个Message.From,同样存在多个Message.From无效并且会被拒绝,但经测试实际上部分客户端是没有遵循上面说的拒绝邮件规则的:

(a) iCloud.com (Web) 在面对多Message.From的情况时,DMARC会验证其第一个Message.From并且给客户端展示的是最后一个Message.From,测试方法对应Espoofer – server_a8;

(b) Mail.ru的邮件服务器会拒接多个Message.From的情况,但是可以使用堆叠的空格可以进行绕过。随后其DMARC可以识别第一个Message.From来进行校验并在Outlook (Windows) 上展现正确格式的第二个Message.From给客户端用户,测试方法对应Espoofer – server_a11;

(c) Fastmail.com的邮件服务器和Fastmail.com (Web) 无法成功识别空格,DMARC会校验格式正确的第一个Message.From,但Fastmail.com的邮件服务器在转发给Fastmail.com (Web) 客户端时除去了空格,并展示给用户的是最后一个Message.From,测试方法对应Espoofer – server_a10。

代替发件人地址进行绕过

Sender字段定义为代发用户,Message.From的作用有两点:1.用于DMARC对齐 2.显示发件人,当邮件没有Message.From的时候,部分组件会找一些标识来代替Message.From:

(d) Naver.com的邮件服务器成功识别了堆叠的Message.From字段,但是在Outlook (Windows) 上面去无法展示堆叠的Message.From字段,此时会使用Sender来展示发件人,测试方法对应Espoofer – server_a12。

(f) Gmail.com的邮件服务器有严格的格式校验会拒绝多Message.From字段的邮件并且当Message.From不存在时会使用Smtp.From来添加一个新的头。当攻击者使用带开头空格的Message.From作为第一个头,Resent-From标头作为备用标头并将Smtp.From置空的情况下,Gmail.com的邮件服务器会首先将空格开头的Message.From标头视为第一个FROM头,且顺利进行DMARC校验,随后插入一个身份验证的DMARC标签头,同时会将空格开头的Message.From也转发给Gmail.com (Web)导致其不识别此Message.From而是显示Resent-From。

 

② 邮件地址不一致性

一个有效的Message.From头的结构图下:

  • Display Name显示名称是一个可选字段用于表示发件人名称,并不受SPF、DKIM、DMARC保护,常用作伪装发件人名称;
  • Comments注释在前面也有所提到,可以自由的插入打破From头中的许多地方,按照标准样例:“From: Pete(A nice \) chap) ” 同样是有效的地址;
  • Route portion路由部分是早期用于定义的功能,@为每个列表的开头,列表通过,分隔,最终以冒号结尾;
  • Real address真实地址代表真实发件人,@前面的部分是可以带引号或不带引号的字符串;
  • Multiple address lists发件人地址列表,可以定义多个满足有效的Message.From头的邮箱。
  • Quoted-pair当遇到特殊解释的字符,例如逗号或者引号,发件人可以使用\来转义;
  • Encoding期初SMTP在邮件头中只支持US-ASCII字符,RFC 2047定义了2中编码方式:B (Base64编码)和Q (带引号编码)格式为:=?charset?encoding?encoded-text?=
    From: bob<b@b.com> => From: =?utf-8?B?Ym9i?=<b@b.com>
    

服务器与客户端关于头文件内容解析的差异性

1.Tutanota.com的邮件服务器只用第一个地址进行DMARC检测,而Web客户端显示只显示第二个地址(a);
2.Yahoo.com、Outlook.com、iCloud.com、Fastmail、Zoho.com和Tutanota.com 的邮件服务器并不能识别编码地址从而用attack.com进行DMARC对齐检测,但是 Gmail.com (Web), Outlook.com (Web), Yahoo.com (Web), Naver.com (Web), Mail (MacOS), Mail (Windows) and Mail (iOS)的客户端是支持编码显示的,所以会显示第一个地址(b);
3.Fastmail.com的邮件服务器不解析路由格式,会将attack.com视为真实地址进行DMARC对齐认证,而其web客户端会只显示第二个地址(c),其他也类似。

其他问题

SPF,DKIM和DMARC通过依赖域查询进行发件人身份验证。如果无法获取域记录,则校验组件可能认为域未部署相应的安全机制从而跳过校验。

1.不可见字符插入目标域地址

例如,Message.From为From:admin@legitimate.com\u2000,Outlook.com (Server) 会去legitimate.com\u2000进行DMARC策略查找并未发现DMARC对齐设置,并且web客户端会显示legitimate.com

2.编码目标域地址

例如,Message.From为From: base64encode(admin@legitimate.com),Yahoo.com (Server) 同样回去编码地址进行DMARC策略查找,并且其web客户端会显示legitimate.com

3.From空绕过

例如,当From头为空但是Sender头存在,Outlook.com (Server),Zoho.com (Server)以及Tutanota.com (Server) 会跳过DMARC校验或者生成”none“结果传递给Message,但是他们的web客户端会显示Sender的地址。

 

Ⅳ.重放攻击

DKIM的校验存在2个可以被利用的点

1.DKIM不能防止重放攻击
2.DKIM在一定情况下允许将其他电子邮件标头(在某些情况下甚至是正文内容)附加到原始邮件中

结合这两个弱点,由合法域签名的邮件可以由重放的攻击者在不破坏DKIM签名的情况下添加恶意内容,并且通过DKIM处理与MUA表达不一致性进一步欺骗电子邮件客户端显示攻击者指定的内容。

 

① DKIM 签名重放

Header spoofing

前面说了DKIM中的h=标签用于说明DKIM签名的字段,在RFC 6376中列出了应该签名的19个标头,但是只有From是强制签名的

1.存在不同域名设置的DKIM签名内容标准是不一样的情况,存在重放篡改的可能,如:

aa.comDKIM设置为h=from,故在重放的过程中可以修改未被校验的头,如直接设置一个Content-Disposition:attachment;filename=ticket.jpg头,则原始内容会被渲染为附件;

2.有时强制签名了关键字段防止篡改,但仍然存在DKIM组件以及客户端渲染的差异使重放的时候进行混淆的可能。在RFC 6376 § 5.4.2中指定了如果消息有多个重复的标头,则DKIM需要使用最后一个标头进行签名,但有的客户端在展示的时候往往会显示第一个标头。

Body spoofing

除了欺骗头之外,攻击者还可以通过利用DKIM-Signature标头中的可选l =标签来欺骗电子邮件正文,该标签表示签名中包含的电子邮件正文的长度。例如,Google网上论坛通常会在每封转发的电子邮件的末尾附加退订信息。这种行为可能会破坏DKIM验证,这时就会使用l =标签,此时重放攻击者就在不破坏DKIM签名的情况下将新的恶意内容附加到原始电子邮件正文中。

举例,如下图所示:

1.discover.com的签名中使用l =的标记,并且Gmail服务器采用了重复标头的最后一个实例进行DKIM验证,故篡改的电子邮件通过了Gmail的DKIM验证;
2.当Gmail Web界面显示此消息时,它会使用攻击者定义的每行第二个MIME格式,并且仅显示攻击者篡改的内容。

 

② 已有邮箱帐户欺骗

当拥有一个想要伪造域名的账号密码时,可能会在使用自定义的MUA通过认证服务发送电子邮件的情况下存在身份绕过

Gmail.com (Server) 绕过为例:

1.攻击者拥有一个发送方user的账号密码
2.电子邮件提供端使用AUTH命令中携带的用户密码对MUA进行身份认证
3.电子邮件接收端会使用Message.From头admin@a.com \,<user@a.com>的第二个用户与MUA用户进行校验
4.通过验证,进行DKIM签名,并发送给对方邮件服务器
5.对方邮件服务器收到进行SPF、DKIM、DMRAC校验并顺利通过

该利用点主要在于如何更改Message.From头的格式让MUA顺利通过认证服务器的用户核实进行发信。

 

③ 重放绕过DKIM签名

通过拦截认证过DKIM的邮件并进行添加From、To头并进行重放,利用前面提到对重复头的差异性进行绕过(可以尝试对严格进行Message.From验证的进行绕过)

绕过过程如下:

1.攻击者拥有一个a.com的user账号密码
2.电子邮件提供端使用AUTH命令中携带的用户密码对MUA进行身份认证
3.进行DKIM签名后发送邮件到攻击者的attack.com
4.攻击者添加重复的From头以及重复的To头,重放给victim邮件服务器
5.其DKIM组件可能只验证原始的From报头,从而通过DKIM认证
6.配合其他SPF绕过方式组合最终绕过DMARC校验

 

0x04 如何防御

1.使用强校验模式进行DMARC验证
2.用户UI需要更明确的安全提示
3.永远不要轻易相信收件人地址

 

0x05 写在后面

如果想在某些攻防项目中大规模使用上述相关邮件伪造手法,通过部分实践,觉得你要有几点需要解决:
1.组合拳
了解每个绕过方式的作用,根据想要伪造的邮服防护措施来定制组合绕过方法
2.发信源
拥有可以使用25端口并且可以大批量发送邮件的可信IP源

(完)