渗透基础——利用IMAP协议读取邮件
0x00 前言
在渗透测试中,当我们获得了用户的邮箱凭据,需要对邮箱内容进行分析时,可以选择通过IMAP协议实现自动化来提高效率。
本文以Exchange为例,介绍通过IMAP协议下载邮件和附件的方法,开源代码,分享脚本编写细节。
0x01 简介
本文将要介绍以下内容:
- 基础知识
- Exchange开启IMAP功能和登录日志
- Python3实现细节
- 开源代码
0x02 基础知识
1.IMAP
全称是Internet Mail Access Protocol,即交互式邮件存取协议
是一种邮件获取协议,可以从邮件服务器上获取邮件的信息
使用端口143
2.IMAP4_SSL
全称是IMAP over SSL,是IMAP协议基于SSL安全协议之上的一种变种协议
继承了SSL安全协议的非对称加密的高度安全可靠性,可防止邮件泄露,也是用来接收邮件的
使用端口993
3.Python3 imaplib库
官方文档:
https://docs.python.org/3/library/imaplib.html
该模块定义了三个类,IMAP4,IMAP4_SSL和 IMAP4_stream
为了提高安全性,我们通常使用用于安全连接的子类IMAP4_SSL
4.Python3 email库
官方文档:
https://docs.python.org/3/library/email.html
当我们使用imaplib库读取邮件时,需要使用email库将接收的消息转换为EmailMessage对象,可以更加方便的对邮件内容进行处理
0x03 Exchange开启IMAP功能和登录日志
默认情况下,Exchange中未启用IMAP4客户端连接
参考资料:
https://docs.microsoft.com/en-us/exchange/clients/pop3-and-imap4/configure-imap4?view=exchserver-2019
开启方法如下:
1.启动IMAP4服务,并将服务配置为自动启动
Powershell命令如下:
Start-Service MSExchangeIMAP4; Start-Service MSExchangeIMAP4BE
Set-Service MSExchangeIMAP4 -StartupType Automatic; Set-Service MSExchangeIMAP4BE -StartupType Automatic
2.配置IMAP4设置
格式如下:
Set-ImapSettings -ExternalConnectionSettings "<FQDN1>:<TCPPort1>:<SSL | TLS | blank>", "<FQDN2>:<TCPPort2>:<SSL | TLS | blank>"... -X509CertificateName <FQDN> [-SSLBindings "<IPv4Orv6Address1>:<TCPPort1>","<IPv4Orv6Address2>:<TCPPort2>"...] [-UnencryptedOrTLSBindings "<IPv4Orv6Address1>:<TCPPort1>","<IPv4Orv6Address2>:<TCPPort2>"...]
Powershell命令实例:
Set-ImapSettings -ExternalConnectionSettings "mail.test.com:993:SSL","mail.test.com:143:TLS" -X509CertificateName mail.test.com
3.重新启动IMAP4服务
Powershell命令如下:
Restart-Service MSExchangeIMAP4; Restart-Service MSExchangeIMAP4BE
4.查看配置:
Powershell命令如下:
Get-Service MSExchangeIMAP4; Get-Service MSExchangeIMAP4BE
Get-ImapSettings | Format-List *ConnectionSettings,*Bindings,X509CertificateName
使用邮箱用户登录OWA,选择Settings
->Options
,能够看到IMAP配置,如下图
默认情况下,Exchange中未启用日志功能
参考资料:
https://docs.microsoft.com/en-us/exchange/configure-protocol-logging-for-pop3-and-imap4-exchange-2013-help
开启方法如下:
1.开启日志功能
Powershell命令如下:
Set-ImapSettings -Server "CAS01" -ProtocolLogEnabled $true
2.重启服务
重新启动IMAP4服务,Powershell命令如下:
Restart-Service MSExchangeIMAP4; Restart-Service MSExchangeIMAP4BE
3.查看配置信息:
Powershell命令如下:
Get-ImapSettings | Format-List ProtocolLogEnabled,LogFileLocation,LogPerFileSizeQuota,LogFileRollOverSettings
默认的日志保存路径为:C:\Program Files\Microsoft\Exchange Server\V15\Logging\Imap4
0x04 Python3实现细节
测试代码1
import imaplib
M = imaplib.IMAP4_SSL('192.168.1.1','993')
M.login('User1', 'Password')
data = M.list()
print(data)
M.logout()
以上代码用来获得所有邮箱文件夹对应的名称
(1)M.list()
用来列出邮箱文件夹的名称
注:
不同的邮件系统只有收件箱名称统一默认为INBOX,发件箱的名称一般不同,例如Exchange的发件箱名称为"Sent Items"
测试代码2
import imaplib
M = imaplib.IMAP4_SSL('192.168.1.1','993')
M.login('User1', 'Password')
M.select('INBOX')
typ, data = M.search(None, 'ALL')
for num in data[0].split():
typ, data = M.fetch(num, '(RFC822)')
print('Message %s\n%s\n' % (num, data[0][1]))
M.close()
M.logout()
以上代码用来读取收件箱所有邮件的内容
(1)M.select('INBOX')
表示选择收件箱
如果换成读取Exchange的发件箱,对应的代码为M.select('"Sent Items"')
如果添加参数2为False,表示设置了只读标志,不允许修改邮箱,示例:M.select('"Sent Items"',False)
(2)typ, data = M.search(None, 'ALL')
中,None
表示使用默认的ASCII编码,ALL
表示搜索条件为所有邮件
如果想要筛选出发件人为user2
的邮件,对应语句为typ, msgnums = M.search(None, '(FROM "user2")')
M.search()
返回的结果为邮件的序列号,例如我的测试环境下,收件箱有9个邮件,此时返回的结果为:
[b'1 2 3 4 5 6 7 8 9']
注:
这里需要区分邮件序列号和UID
邮件序列号为从1开始累加的数列,UID是区分邮件的唯一标识
获得邮件序列号同UID对应关系可使用以下代码:
import imaplib
M = imaplib.IMAP4_SSL('192.168.1.1','993')
M.login('User1', 'Password')
M.select('INBOX')
typ, data = M.search(None, 'ALL')
for num in data[0].split():
typ, data = M.fetch(num, 'UID')
print(data)
M.close()
M.logout()
(3)M.fetch(num, '(RFC822)')
用来提取邮件消息
参数1num
表示提取的邮件序列号
参数1支持同时提取多个连续邮件消息,例如同时提取邮件序列号为2-5的邮件命令为M.fetch('2:5', '(RFC822)')
参数2'(RFC822)'
表示数据项名称,这里’(RFC822)’等同于BODY[]
,只返回邮件体文本格式和大小的摘要信息
如果只想获得邮件头部的内容,可以使用以下代码:
M.fetch(num, 'BODY[HEADER]')
如果只想获得邮件体的内容,可以使用以下代码:
M.fetch(num, 'BODY[TEXT]')
(4)M.close()
用来关闭当前选择的邮箱
在执行完M.select()
后使用
测试代码3
import imaplib
import email
M = imaplib.IMAP4_SSL('192.168.1.1','993')
M.login('User1', 'Password')
M.select('INBOX')
typ, data = M.search(None, 'ALL')
for num in data[0].split():
typ, data = M.fetch(num, '(RFC822)')
msg = email.message_from_bytes(data[0][1])
for part in msg.walk():
if part.get('Content-Disposition'):
fileName = part.get_filename()
if bool(fileName):
with open(fileName,'wb') as f:
f.write(part.get_payload(decode=True))
M.close()
M.logout()
以上代码用来保存收件箱所有邮件的附件
(1)msg = email.message_from_bytes(data[0][1])
用来将数据转换为email对象
(2)msg.walk()
用来遍历邮件对象的所有部分
(3)part.get('Content-Disposition')
用来获得对应字段名Content-Disposition
的字段值
如果邮件包含附件,将会带有字段Content-Disposition
,通过这个判断邮件是否包含附件
(4)part.get_filename()
用来获得信息头当中Content-Disposition
字段当中名为filename
的参数值,对应附件的名称
(5)part.get_payload(decode=True)
用来获得附件内容
由于附件内容是以Base64编码的形式存储,所以在读取时需要加入参数decode=True
作Base64解码
测试代码4
import imaplib
import email
M = imaplib.IMAP4_SSL('192.168.1.1','993')
M.login('User1', 'Password')
M.select('INBOX')
typ, data = M.search(None, 'ALL')
for num in data[0].split():
typ, data = M.fetch(num, '(RFC822)')
msg = email.message_from_bytes(data[0][1])
with open(num.decode('utf8') + '.eml','wb') as f:
f.write(bytes(msg))
M.close()
M.logout()
以上代码用来逐个保存收件箱的所有邮件,以邮件序列号为名称,后缀名为eml,可以使用Outlook打开
0x05 开源代码
–
我已经将完整的代码上传至github,地址如下:
https://github.com/3gstudent/Homework-of-Python/blob/master/imapManage.py
代码支持以下功能:
- 查看文件夹配置
- 从收件箱下载所有附件
- 从发件箱下载所有附件
- 从收件箱下载所有邮件
- 从发件箱下载所有邮件
在下载文件时,首先以邮箱用户名创建文件夹,保存对应用户下载的文件
默认支持通过IMAP4_SSL访问Exchange邮件,对于不同的邮件系统,收件箱没有区别,发件箱的名称有所不同。发件箱的名称可以通过CheckConfig
命令查询文件夹对应的名称进行修改
代码修复了附件名称因为编码问题无法识别的bug
为了便于记录邮件访问过程,加入了日志记录功能
0x06 小结
本文以Exchange为例,介绍通过IMAP协议下载邮件和附件的方法,开源代码imapManage.py,分享脚本编写细节。对于其他邮件系统,可以参照此代码只需要修改发件箱的名称即可。