0x01 SMTP协议

smtp协议是简单邮件传送协议,它工作在C/S模式下,用来提供发送邮件的服务。那么为什么我们现在发送邮件可以通过登录web的方式实现?因为我们通过浏览器提交身份认证和发送邮件的数据给qq邮箱或网易邮箱的web服务器后,web服务器会将数据转给其邮件服务器,让邮件服务器完成邮件投递工作,这就是为什么我们现在可以不用安装邮件客户端如foxmial、outlook仍然能发送邮件的原因。

0x02邮件的收发过程

电子邮件通信系统.JPG

1、发信人在用户代理里编辑邮件,包括填写发信人邮箱、收信人邮箱和邮件标题等等。
2、用户代理提取发信人编辑的信息,生成一封符合邮件格式标准(RFC822)的邮件。
3、用户代理用SMTP将邮件发送到发送端邮件服务器(即发信人邮箱所对应的邮件服务器)。
4、发送端邮件服务器用SMTP将邮件发送到接收端邮件服务器(即收信人邮箱所对应的邮件服务器)。
5、收信人调用用户代理。用户代理用POP3协议从接收端邮件服务器取回邮件。
6、用户代理解析收到的邮件,以适当的形式呈现在收信人面前。

其中两个过程涉及到smtp协议,1、客户端到发送端邮件服务器,这个过程邮件服务器需要验证客户端身份,严格意义上来说,这个叫ESMTP,smtp不做用户身份认证。
2、发送端邮件服务器到接收端邮件服务器,这个过程不需要进行身份认证。

0x03 SMTP RFC文档

RFC版本时间说明URL
RFC 8211982/08初始版本https://tools.ietf.org/html/rfc821
RFC 9741986/01域名系统需求和实现相关https://tools.ietf.org/html/rfc974
RFC 10351987/11域名系统需求和实现相关https://tools.ietf.org/html/rfc1035
RFC 18691995/11ESMTP规格扩展https://tools.ietf.org/html/rfc1869
RFC 28412001/04-https://tools.ietf.org/html/rfc2841
RFC 53212008/10-https://tools.ietf.org/html/rfc5321

0x04 SMTP通讯过程

这里以利用foxmail客户端到qq邮件服务器为例,用wireshark抓包分析SMTP通讯过程。

1、客户端对邮件服务器25端口进行TCP三次握手

Snipaste_2019-10-27_00-02-32.png

2、三次握手成功后,服务器主动推送服务就绪信息

网易邮箱一般都形如“220 163.com Anti-spam GT for Coremail System (163com[20111010])”;QQ邮箱形如“220 smtp.qq.com Esmtp QQ Mail Server”;Google邮箱形如“220 mx.google.com ESMTP nw8sm917193igc.7”。其中220代表服务就绪,每一条服务就绪信息以“rn”为结尾标示符。

3、客户端向服务器说明身份

交代自己认证SMTP服务器的机器名,例如我使用的windows系统的计算机名叫“DESKTOP-465M1IO”,则发送“EHLO DESKTOP-465M1IO”。

4、如果身份有效,则服务器进入等待认证状态,主动推送自身支持的所有SMTP认证方式

QQ邮箱发送的内容如下:

250-smtp.qq.com
250-PIPELINING
250-SIZE 73400320
250-STARTTLS
250-AUTH LOGIN PLAIN
250-AUTH=LOGIN
250-MAILCOMPRESS
250 8BITMIME

表示其支持PLAIN、LOGIN两种认证方式;
LOGIN方式
使用login方式的验证序列如下 (C:表示Client,S:表示Server)
C:auth login ------------------------------------------------- 进行用户身份认证
S:334 VXNlcm5hbWU6 ----------------------------------- BASE64编码“Username:”
C:Y29zdGFAYW1heGl0Lm5ldA== ----------------------------------- 用户名,使用BASE64编码
S:334 UGFzc3dvcmQ6 -------------------------------------BASE64编码"Password:"
C:MTk4MjIxNA== ----------------------------------------------- 密码,使用BASE64编码
S:235 auth successfully -------------------------------------- 身份认证成功

PLAIN方式
基于明文的SMTP验证
其发送用户名与口令的格式应该是<NULL>tim<NULL>tanstaaftanstaaf。“tim”是用户名,后边的字符串是口令,NULL是ASCII的0(所以无法使用telnet登录)。

5、客户端判断自身是否支持服务器提供的SMTP认证方式

如果认证方式指定“auto”则采用服务端提供的第一个认证方式,如果指定其他方式,则判断服务端是否支持该方式,否则返回错误。
这一歩相当关键,因为客户端程序可以根据具体的认证方式加载相应插件来完成认证过程。

6、客户端向服务器请求认证

发送“AUTH LOGIN”。

7、如果认证请求合理,服务器将进入等待用户输入状态

发送“334 VXNlcm5hbWU6”,334表示等待客户端输入,VXNlcm5hbWU6表示等待输入用户名。

8、客户端向服务器发送转码后的用户名

发送经过Base64转码后的用户名,例如用户名是“test”,那么就发送“dGVzdA”。

9、服务器再次进入等待用户输入状态

发送“334 UGFzc3dvcmQ6”,334表示等待客户端输入,UGFzc3dvcmQ6表示等待输入密码。

10、客户端向服务器发送转码后的密码

发送经过Base64转码后的密码,例如密码是“123456”,就发送“MTIzNDU2”。

11、如果用户名或者密码出错,服务器将返回530错误,发送“530 Access denied”,表示认证失败。否则将返回235,发送“235 Authentication successful”,表示用户认证成功。

12、客户端告诉服务器邮件来自何方

发送“MAIL FROM: <[email protected]> SIZE=988887”。

13、如果合理,服务端返回250表示成功

发送“250 OK”。

14、客户端告诉服务器邮件去往何地

发送“RCPT TO: <[email protected]>”。

15、如果合理,服务器返回250表示成功

发送“250 OK”。

16、客户端告诉服务器自己准备发送邮件正文

发送“DATA”。

17、服务器返回354,表示自己已经作好接受邮件的准备

发送“354 End data with .”,提醒客户端开始发送邮件并以“.”结束。

18、客户端发送邮件正文(如果正文过长,可以分多次发送)

对于邮件正文,RFC822(Standard for ARPA Internet Text Messages)文档定义了邮件内容的主体结构和各种邮件头字段的详细细节,但是,它没有定义邮件体的格式,RFC822文档定义的邮件体部分通常都只能用于表述一段普通的文本,而无法表达出图片、声音等二进制数据。所以为了通过邮件传输各种编码的文件,定义MIME协议(Multipurpose Internet MailExtension,多用途Internet邮件扩展),对基于RFC822邮件格式的扩展,目前大部分邮件传输正文也是应用MIME协议。

MIME消息由消息头和消息体两大部分组成。现在我们关注的是MIME邮件,因此在以下的讨论中姑且称“消息”为“邮件”。
(1)邮件头
MIME格式的邮件头包含了发件人、收件人、主题、时间、MIME版本、邮件内容的类型等重要信息。每条信息称为一个域,由域名后加“: ”和信息内容构成,可以是一行,较长的也可以占用多行。域的首行必须“顶头”写,即左边不能有空白字符(空格和制表符);续行则必须以空白字符打头,且第一个空白字符不是信息本身固有的,解码时要过滤掉。常用邮件头如下:

域名含义添加者
Received传输路径各级邮件服务器
Return-Path回复地址目标邮件服务器
Delivered-To发送地址目标邮件服务器
Reply-To回复地址邮件的创建者
From发件人地址邮件的创建者
To收件人地址邮件的创建者
Cc抄送地址邮件的创建者
Bcc暗送地址邮件的创建者
Date日期和时间邮件的创建者
Subject主题邮件的创建者
Message-ID消息ID邮件的创建者
MIME-VersionMIME版本邮件的创建者
Content-Type内容的类型邮件的创建者
Content-Transfer-Encoding内容的传输编码方式邮件的创建者

以下为邮件头案例:

Date: Sat, 26 Oct 2019 15:37:18 +0800
From: "[email protected]" <[email protected]>
To: xxxxx <[email protected]>
Cc: xxxx <[email protected]>
Subject: =?GB2312?B?08q8/nRlc3SjrNXiysfW98zi?=
X-Priority: 3
X-Has-Attach: yes
X-Mailer: Foxmail 7.2.13.365[cn]
Mime-Version: 1.0
Message-ID: <[email protected]>
Content-Type: multipart/mixed;

MIME邮件扩展了RFC822文档中已经定义了的邮件头字段的内涵,例如,定义了subject头字段中的值内容的格式,以便通过编码的方式让邮件主题中也可以使用非ASCII码的字符。subject头字段中的值嵌套在一对“=?”和“?=”标记符之间,标记符之间的内容由三部分组成:邮件主题的原始内容的字符集、当前采用的编码方式、编码后的结果,这三部分之间使用“?”进行分隔。案例中对包含有非ASCII码字符的邮件主题进行了编码后的结果:

Subject: =?GB2312?B?08q8/nRlc3SjrNXiysfW98zi?=

其中,“Gb2312”部分说明邮件主题的原始内容为gb2312编码的字符文本,“B”部分说明对邮件主题的原始内容按照BASE64方式进行了编码,“08q8/nRlc3SjrNXiysfW98zi”为对邮件主题的原始内容进行了BASE64编码后的结果。

如果需要了解MIME的详细细节,可以查阅RFC2045~2049系列文档。

(2)邮件体

  邮件内容有各种各样的(既纯文本,超文本,内嵌资源(比如内嵌在超文本中的图片),附件的组合),服务器如何知道该邮件是哪些的混合呢?通过第一个content-type,如果是纯文本该头为:

Content-Type: text/plain; charset=GBK 如果包含了其他内容,邮件体被分为多个段,段中可包含段,每个段又包含段头和段体两部分。content-type为multipart类型。multipart类型分为三种,这三种的关系如下:
680546-20170519200206510-840274572.png
可以看出,如果在邮件中要添加附件,必须定义multipart/mixed段;如果存在内嵌资源,至少要定义multipart/related段;如果纯文本与超文本共存,至少要定义multipart/alternative段。什么是“至少”?举个例子说,如果只有纯文本与超文本正文,那么在邮件头中将类型扩大化,定义为multipart/related,甚至multipart/mixed,都是允许的。  

multipart诸类型的共同特征是,在段头指定“boundary”参数字符串,段体内的每个子段以此串定界。所有的子段都以“--”+boundary行开始,父段则以“--”+boundary+“--”行结束。段与段之间也以空行分隔。在邮件体是multipart类型的情况下,邮件体的开始部分(第一个“--”+boundary行之前)可以有一些附加的文本行,相当于注释,解码时应忽略。
以下为邮件体案例:

Content-Type: multipart/mixed;
boundary="----=_001_NextPart166634325136_=----"

This is a multi-part message in MIME format.

------=_001_NextPart166634325136_=----
Content-Type: multipart/related;
    boundary="----=_002_NextPart418455856474_=----"


------=_002_NextPart418455856474_=----
Content-Type: multipart/alternative;
    boundary="----=_003_NextPart021017628760_=----"


------=_003_NextPart021017628760_=----
Content-Type: text/plain;
    charset="GB2312"
Content-Transfer-Encoding: base64

DQrTyrz+suLK1KOs1eLKx9PKvP7V/c7EDQoNCg0KMjgwOTEwMDQxMkBxcS5jb20NCg==

------=_003_NextPart021017628760_=----
Content-Type: text/html;
    charset="GB2312"
Content-Transfer-Encoding: quoted-printable

<html><head><meta http-equiv=3D"content-type" content=3D"text/html; charse=
t=3DGB2312"><style>body { line-height: 1.5; }body { font-size: 10.5pt; fon=
t-family: 'Microsoft YaHei UI'; color: rgb(0, 0, 0); line-height: 1.5; }</=
style></head><body>=0A<div><span></span><br></div>=0A<div>=D3=CA=BC=FE=B2=
=E2=CA=D4=A3=AC=D5=E2=CA=C7=D3=CA=BC=FE=D5=FD=CE=C4<img src=3D"cid:_Foxmai=
l.1@5042ffb2-7004-deba-1c0d-b9541196155e" border=3D"0" style=3D"font-size:=
 10.5pt; line-height: 1.5; background-color: transparent;"></div><hr style=
=3D"width: 210px; height: 1px;" color=3D"#b5c4df" size=3D"1" align=3D"left=
">=0A<div><span><div style=3D"MARGIN: 10px; FONT-FAMILY: verdana; FONT-SIZ=
E: 10pt"><div>[email protected]</div></div></span></div>=0A</body></html>
------=_003_NextPart021017628760_=------

------=_002_NextPart418455856474_=----
Content-Type: image/jpeg;
    name="InsertPic_33AB.jpg"
Content-Transfer-Encoding: base64
Content-ID: <_Foxmail.1@5042ffb2-7004-deba-1c0d-b9541196155e>

[base64编码数据]

------=_002_NextPart418455856474_=------

------=_001_NextPart166634325136_=----
Content-Type: application/octet-stream;
    name="test.zip"
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
    filename="test.zip"

[base64编码数据]

------=_001_NextPart166634325136_=----
Content-Type: application/octet-stream;
    name="test.jpg"
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
    filename="test.jpg"

[base64编码数据]

------=_001_NextPart166634325136_=------

消息体包含3段,首先声明了_001_NextPart包含附件,_002_NextPart包含邮件正文的内嵌资源,_003_NextPart就是邮件正文。之后最先展示邮件正文的纯文本文件,是base64编码过后的txt文本文件,然后是quoted-printable编码过后的html,由于正文中添加了一个图片,所有在html中引用了该图片<img src=3D"cid:_Foxmai=l.1@5042ffb2-7004-deba-1c0d-b9541196155e"。
_002_NextPart则是被正文引用的图片,所以会多一个声明来对应正文的引用 Content-ID: <_Foxmail.1@5042ffb2-7004-deba-1c0d-b9541196155e>。最后_001_NextPart则是两个附件的内容。

19、客户端发送完正文以后,紧接着发送结束符

发送“.”。

20、如果合理,服务端返回250表示成功

发送“250 Ok: queued as”。

21、邮件发送结束,客户端请求断开连接

发送“QUIT”。

22、服务器返回211,提示断开申请被采纳,并主动断开连接,整个邮件发送过程结束。

发送“221 Bye”。

附:如果服务端传过来的错误码后面紧跟这”-“,则说明该次消息分了很多节,直到最后一节没有”-“为止。

0x05 流量还原

1、借助邮件客户端直接还原
借助邮件客户端直接还原是最快且最方便的一种方法,利用wireshark直接追踪smtp的流量,然后保存为.eml格式,再使用foxmail等邮件客户端直接打开.eml格式文件,便可以直接提取出正文和附件。
这种方式的缺点是,如果邮件流量不完整,可能会遇到无法提取的情况。
Snipaste_2019-10-28_00-01-53.png
Snipaste_2019-10-26_18-23-49.png
2、根据提示字段手工提取
对MIME协议有很好的了解后,便可以清晰识别邮件正文和附件,从而根据字段进行相应解码提取文件。
例如复制出邮件超文本正文到notepad++中后,选中所有内容,用插件-MIME工具-Quoted-printable-Decode将超文本解码,然后再修改显示编码为GB2312,保存为.html文件,邮件正文便还原出来了。同理,附件及正文中的内嵌资源也是如此还原。
手工提取的缺点是,如果流量附件很多,需要一个一个把附件的base64编码后的流量摘出来,比较耗费时间。

参考文档:
https://blog.csdn.net/bripengandre/article/details/2191048
https://blog.csdn.net/liumiaocn/article/details/81131420
https://blog.csdn.net/woshinia/article/details/8994833
https://blog.csdn.net/sinat_24773437/article/details/73477872
https://blog.csdn.net/qq_34227896/article/details/80326121
http://blog.sina.com.cn/s/blog_9ed51a090101664x.html
Last modification:November 10th, 2021 at 01:01 pm