安全路透社
当前位置:安全路透社 > 安全客 > 正文

【技术分享】一封伪造邮件引发的研究


0x00. 前言


我用swaks 发送一封以我们公司CTO为显示发件人(腾讯企业邮箱)的伪造邮件给我的一个同事,邮件的内容就是让这位同事去CTO的办公司一趟,没想到这位同事真的去了,然后一脸懵逼的回来了

恶作剧算是完了,但是这让我开始研究伪造邮件是为什么产生的,腾讯企业邮为什么没有拦截

0x01.  关于伪造邮件的一些概念


1) 邮件服务商之间转发邮件是不需要认证的,也就是说MTA 到MTA之间转发邮件是不需要认证的,这是SMTP协议本身定义的。 所以协议钓鱼邮件就可以伪称来自某某MTA发送钓鱼邮件

 2) 互联网上有一些邮件域名没有配置SPF记录 或者SPF记录值设置不当,就会被用作伪造邮件的mail_from 后缀域名

比如freebuf.com 

3) 我们平常必须登录才能发送邮件(一般用的发邮件工具称作MUA,比如foxmail等),这是因为邮件服务商人为要求的,这不是SMTP协议本身要求的,SMTP协议本身是不需要身份认证的

4) mail_from 和from 的区别

mail_from: 是信封上的发件人,由[前缀@域名]组成,是实际发件人

from: 信封内容里的发件人。 也就是我们平时

如果mail_from (实际发件人) 和 from (宣称的发件人) 不一致,则收到的邮件会显示 本邮件由<实际发件人>代发,以提醒收件人两者的不同

http://p6.qhimg.com/t01e945f48db3f44833.png

有的ESP(邮件服务商)并不会要求mail_from 和from完全一致,而只是要求两者的域名相同(比如QQ 邮箱 和Gmail邮箱)

下面是Gmail邮箱收到的一封<码农周刊>发送的邮件,mail_from 和from 不完全一致, 但没有提示代发

http://p6.qhimg.com/t015741fe9885a0b649.png

是调用sendCloud 的API 进行发件的,由于SendCloud 对mail_from 的前缀(@前面的)用的是随机字符串,所以遇到严苛的ESP(mail_from 和from 必须完全一致才不显示代发,比如网易邮箱), 那就爱莫能助了

5) 一个腾讯企业邮特殊的例子

这是一封腾讯企业邮的收到的伪造邮件(mail_from 和from不一致), mail_from 是xxx@xxx.com from是xxx@xxx.cn

mail_from 和from 的后缀中就cn 和com 不同,也就是说只有顶级域名不同,其他相同

这样腾讯企业有竟然没有代发提示、安全提示,正常的出现在了我的收件箱中, 不管mail_from 中后缀xxx.com 的SPF是不是OK,

也不管xxx.com是不是存在

2、DKIM

国外用的比较多,国内不多,比如腾讯邮箱默认就不支持这个

下图是一封腾讯企业邮发送到Gmail邮箱的邮件部分原始邮件信息:

http://p0.qhimg.com/t0172a0854dfee898fd.png

可以看到并没有DKIM签名

而Gmail默认是有DKIM签名的

下图是一封Gmail邮箱发送到腾讯企业的邮件部分原始邮件信息:

http://p2.qhimg.com/t01f02a067bcee77ef7.png

可以看到是有DKIM签名的。

1)关于DKIM的概念

DKIM全称叫"Domain Key Identified Mail”,是yahoo的domainkey技术跟cisco的identified mail合起来的产物,有标准rfc4871、

rfc5762,它的目的主要用来保证邮件的完整性,避免钓鱼。与SPF一样也做Sender authentication,但DKIM做的比SPF更复杂,DKIM会对邮件头

及正文进行签名,没有私钥下,邮件被假冒或篡改后,就会与邮件头签名不一致,从而防止这样的情况。

DKIM签名是先对内容(BODY)部分HASH,然后把这个BODY HASH放到HEADER里面,再对头部做签名。头部也不是所有字段都要签名,只有一些常用的字段,或者比较有意义的。像Received、Return-path、Bcc、Resent-bcc、DKIM-Signature、Comments、Keywords这样的字段一般不签名,FROM则是必须被签名(rfc4871 5.5 Recommended Signature Content), 最后在邮件头中增加一个DKIM-Signature头用于记录签名信息。

接收方则通过DNS查询得到公开密钥后进行验证, 验证不通过,则认为是垃圾邮件,所以DKIM不仅仅可以防止垃圾邮件,还可以防止邮件内容被篡改    

简单来说,DKIM(DomainKeys Identified Mail)是一种电子邮件的验证技术,使用密码学的基础提供了签名与验证的功能。

一般来说,发送方会在电子邮件的标头插入DKIM-Signature及电子签名信息。而接收方则通过DNS查询得到公开密钥后进行验证。

2)邮件域的DKIM配置和查询

邮件接收方通过DNS查询得到公开密钥后进行验证所以说需要在DNS域名解析上中加上一个TXT的记录,用来记录DKIM的公钥信息, 以DNSPOD为例 ,类似SPF记录

以service@mail.vpgame.net为例

在主机记录中写入  mail._domainkey.mail (这里的第一个mail为DKIM中域名的selector,可以修改为不同的值,一个域名可以有多个selector,这样不同的Email server可以有不同的key), 记录类型为TXT, 记录值为:

v=DKIM1;k=rsa;p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCmMPX+sFtBSSBaQENMXIY0kMoU xwpjsktTkjlsrdErh8WKSdRqNEZCE7e5/i9qT/rot5WikkyLoO9nWactl5u5rXli Nqy4eGq3aSQAo0J1/prrL9ZP/NWVo2j6lcSgkMgVCdw7gSIxObfvmp6PIb4edNzP nRBnpjey8xWFTDBzvQIDAQAB

格式类似这样,可能具体的公钥信息不一致, 其中v表示DKIM的版本; k表示非对称的加密算法; p表示base64之后的公钥信息

如何查询邮件域的DKIM 公钥:

windows:

nslookup -qt=txt mail._domainkey.mail.vpgame.net

第一个mail 是上面所说的邮件域的selector,_domainkey 是固定格式(DKIM就是基于domainkeys的技术发展而来), mail.vpgame.net 是邮件域

http://p9.qhimg.com/t01bcfea1a19d40d3d4.png

Linux:

dig -t txt mail._domainkey.mail.vpgame.net

http://p4.qhimg.com/t011d348c9b0d37727e.png

补充一个gmail的:

http://p2.qhimg.com/t01b3afb4be3a8233b7.png

3)DKIM签名信息分析

这是一封Gmail发给我的腾讯企业邮箱的邮件:

http://p7.qhimg.com/t01b8718aee7c21b484.png

我们看一下DKIM-Signature的内容:

其中,v表示DKIM的版本,

a=rsa-sha1,表示算法(algorithm)。有rsa-sha1和rsa-sha256两种,

c=relaxed/relaxed,表示标准化方法(Canonicalization),头部和内容都用的relaxed方法。还可以用simple,表示不能有任何改动,包括空格.

d=gmail.com,发送者的域名, 也就是Gmail收到邮件信息中的所谓的"署名域", 这个"署名域"需要在邮件服务器的DKIM设置中配置的,可以和邮件域(比如service@mail.vpgame.net @后面的即是邮件域)不一样(一般都保持一样)

s=20161025,表示域名的selector,通过这个selector,可以允许一个域名有多个public key,这样不同的server可以有不同的key。

h=…,是header list,表示对HEADER中有哪些字段签名。

bh=…,是body hash。也就是内容的hash。

b=…,是header的签名。也就是把h=那个里面所有的字段及其值都取出来,外加DKIM-signature这个头(除了b=这个值,因为还不存在),一起hash一下,然后用rsa加密。

    

0x03. 关于国内有名的sendCloud配置注意事项


1、发件域和显示发件人(from)的邮件域(@后面的部分) 不一致导致的代发提示

ESP(邮件服务商)在收到邮件的时候都会检查mail_from 和from 的邮件域(@后面的部分)是否一致,不一致则提示邮件代发

gmail也是这样处理

如果你在sendCloud上配置的发件域和邮件显示的发件人的邮件域不一致,则会在gmail邮箱中显示邮件代发

http://p6.qhimg.com/t01596dbdefa8c05278.png

实际发件域是mail.vpgame.net,而显示的发件人的邮件域是mail.vpgame.cn ,两者不一致,Gmail提示代发

下图是一封码农周刊发送到我Gmail邮箱中的一封邮件, 没有提示代发,因为实际发件人的邮件域是和显示发件人的邮件域是一致的

http://p3.qhimg.com/t01d6ecedb5b6a58eb3.png

2、使用非加密端口发送代发邮件

比如上面的mail.vpgame.net 代发的一封邮件就是被显示没有加密,可能是直接调用sendCloud的未加密端口发送的

http://p3.qhimg.com/t01596dbdefa8c05278.png

这里显示sendCloud.org未加密这封邮件, 因为gmail是从sendCloud 收到这封邮件的

0x04. 关于使用foxmail代发邮件


1. foxmail 可以配置显示其他账户(由本邮件代发显示邮件账号)

http://p0.qhimg.com/t01d0d3b9d3822e6237.png

2. 用上图的配置给自己(上图的实际账号)发封邮件

http://p8.qhimg.com/t017e6086a80683ab4e.png

这里会显示代发

3. 如果是微信收到邮件呢(腾讯企业邮箱绑定微信后,微信可收信)

http://p5.qhimg.com/t01f76b49110b849e03.png

不注意看,还真以为是显示的发件人发的邮件呢

4. 给Gmail 也发一封

http://p7.qhimg.com/t01d251e8324e491832.png

Gmail 也没提示代发

但是我们查看Gmail的原始邮件,可以看到此邮件不是显示发件人发的

http://p7.qhimg.com/t01d7f71e7693e26466.png

5. 我们来看回复此邮件能不能看到猫腻

Gmail的回复, 回复给了显示发件人

fomail的回复,也是回复给了显示收件人

http://p7.qhimg.com/t0123239adb939bdc8e.png

foxmail的快速回复, 回复给了实际发件人

http://p5.qhimg.com/t0184c50eeafa4dbf9d.png

注: 如果是回复全部,则包含实际发件人

0x05. 一些识别伪造邮件的小技巧


1、实际发件人与显示发件人不一致

这时候就需要小心了,确认邮件真的是由合法的第三方代发的,比如有名的邮件代发服务商sendCloud,如果不是,一般都是伪造邮件

如何知道邮件的实际发件人?

一般是查看邮件的原始内容,不过还有一个小技巧,就是在收到邮件的时候,邮箱提示信息中显示的就是实际发件人

http://p7.qhimg.com/t011e3942b7e4f00966.png

当然也可以尝试回复一下邮件,这样真实发件人就知道了,对比一下和显示的发件人是否一致,不一致就要小心了

2、一般正常的发件服务器都会配置SPF,有的还会配置DKIM,如果收到的邮件的发件人的邮件域没有配置SPF,则有可能是伪造邮件

3、一般邮件服务商都会有相应的反垃圾邮件的机制,对于有安全提示的邮件要小心,不要轻易相信,不要轻易点击其中图片、链接、附件

http://p2.qhimg.com/t010356cb454b700a5f.png

http://p3.qhimg.com/t01a3c9ba088ebefd7d.png

如上图,都是伪造邮件,而且显示是收件人也是伪造的

0x06. 补充


腾讯企业邮发送的邮件默认是加密的

http://p4.qhimg.com/t01323c50c869fa9d3d.png

一般邮件body 内容是base64-utf8 编码后的结果,可以使用k8-web 编码转换工具解码或者编码

http://p2.qhimg.com/t016b827f082c171de1.png

邮件中的邮件头的from 或者 to 部分都支持中文别名显示(subject也支持中文),这些就需要写代码将中文内容编码一下, 以下是实现代码(python)

    #!/usr/bin/env python
    # -*- coding:utf8 -*-
    
    
    import sys
    from email.header import make_header
    
    
    
    if __name__ == '__main__':
    
         reload(sys)
         sys.setdefaultencoding('utf8')
         content = repr('访问下邮件中的链接,看看不能访问')
         print make_header([('\xe8\xae\xbf\xe9\x97\xae\xe4\xb8\x8b\xe9\x82\xae\xe4\xbb\xb6\xe4\xb8\xad\xe7\x9a\x84\xe9\x93\xbe\xe6\x8e\xa5\xef\xbc\x8c\xe7\x9c\x8b\xe7\x9c\x8b\xe4\xb8\x8d\xe8\x83\xbd\xe8\xae\xbf\xe9\x97\xae', 'utf-8')]).encode()

比如说自己构造邮件原始内容(不是调用某某库哦)的时候想把subject 内容修改一下,则需要先用repr 将中文的16进制编码内容传入make_header的参数中,这种得到的结果就是邮件subject(中文)原始内容

这里要注意一下,不能直接将content传入make_header中,否则会出错,而是先打印repr('subject中文内容')值,然后将其拷贝至make_header中


本文地址:http://bobao.360.cn/learning/detail/4056.html

未经允许不得转载:安全路透社 » 【技术分享】一封伪造邮件引发的研究

赞 (0)
分享到:更多 ()

评论 0

评论前必须登录!

登陆 注册