Good in study, attitude and health

Exchange Web Service(EWS)开发指南5——exchangelib

0x00 前言


在之前的文章介绍了通过SOAP XML message实现利用hash对Exchange资源的访问,由于采用了较为底层的通信协议,在功能实现上相对繁琐,但是有助于理解通信协议原理和漏洞利用。

如果仅仅为了更高效的开发一个资源访问的程序,可以借助Python库exchangelib实现。

本文将要介绍exchangelib的用法,开源代码,实现自动化下载邮件和提取附件。

0x01 简介


本文将要介绍以下内容:

  • exchangelib用法
  • 开发细节
  • 开源代码

0x02 exchangelib用法


参考资料:

https://github.com/ecederstrand/exchangelib

https://ecederstrand.github.io/exchangelib/

1.简单的登录测试

代码如下:

from exchangelib import Credentials, Account, Configuration, DELEGATE
credentials = Credentials(username='MYWINDOMAIN\\myuser', password='topsecret')
config = Configuration(server='outlook.office365.com', credentials=credentials)
account = Account(primary_smtp_address='john@example.com', config=config,
                  autodiscover=False, access_type=DELEGATE)
for item in account.inbox.all().order_by('-datetime_received')[:100]:
    print(item.subject, item.sender, item.datetime_received)

如果Exchange服务器证书不可信,需要忽略证书验证,加入以下代码:

from exchangelib.protocol import BaseProtocol, NoVerifyHTTPAdapter
BaseProtocol.HTTP_ADAPTER_CLS = NoVerifyHTTPAdapter

屏蔽输出的提示信息InsecureRequestWarning,加入以下代码:

import urllib3
urllib3.disable_warnings()

完整代码如下:

from exchangelib import Credentials, Account, Configuration, DELEGATE
from exchangelib.protocol import BaseProtocol, NoVerifyHTTPAdapter
BaseProtocol.HTTP_ADAPTER_CLS = NoVerifyHTTPAdapter
import urllib3
urllib3.disable_warnings()
credentials = Credentials(username='MYWINDOMAIN\\myuser', password='topsecret')
config = Configuration(server='outlook.office365.com', credentials=credentials)
account = Account(primary_smtp_address='john@example.com', config=config,
                  autodiscover=False, access_type=DELEGATE)
for item in account.inbox.all().order_by('-datetime_received')[:100]:
    print(item.subject, item.sender, item.datetime_received)

2.使用明文或hash登录

使用明文登录:

credentials = Credentials('MYWINDOMAIN\\myuser', 'topsecret')

使用Hash登录:

credentials = Credentials('MYWINDOMAIN\\myuser', '00000000000000000000000000000000:7C451851EA87B63EC7692126416D01EB')

3.统计邮件数目

示例代码:

n = a.inbox.all().count()

4.指定时间范围进行搜索

示例代码:

for item in account.inbox.filter(datetime_received__gt=EWSDateTime(2021, 1, 20, tzinfo=account.default_timezone)):
    print(item.subject, item.sender, item.datetime_received)

5.指定下载数量:

指定前10个:

first_ten = a.inbox.all()[:10]

指定后10个:

last_ten = a.inbox.all()[:-10]

指定区间:

next_ten = a.inbox.all()[10:20]

6.文件夹枚举

能够遍历出邮箱用户下的所有文件夹,示例代码:

print(account.root.tree())

7.将Python脚本编译成exe

如果将使用exchangelib开发的Python脚本编译成exe格式,使用pyinstaller -F test.py命令会报错,提示:No time zone found with key UTC

解决方法:

pyinstaller --collect-all tzdata --onefile test.py

0x03 开发细节


1.通信协议

exchangelib也是通过SOAP XML message实现利用hash对Exchange资源的访问

2.邮件保存

exchangelib中会自动XML格式邮件内容进行解析,在保存邮件时,可以直接提取出对应的信息

这里需要注意的是可以将返回结果中的字符串\r\n替换成换行符,提高数据可读性

示例代码:

filtered_items = email.inbox.all()
for item in items:
with open(item.id, "w") as fw:
	fw.write(str(item).replace('\\r\\n','\r\n'))

3.条件匹配

exchangelib支持Advanced Query Syntax (AQS)

AQS参考资料:

https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/querystring-querystringtype

利用AQS可以实现日期搜索,搜索格式示例:

sent:>=2021/1/1 AND sent:<=2021/12/30
received:>=2021/1/1 AND received:<=2021/12/30

对于关键词搜索,无法直接使用AQS,可以选择接收所有邮件再进行字符串匹配

0x04 开源代码


完整代码已上传至github,地址如下:

https://github.com/3gstudent/Homework-of-Python/blob/master/ewsManage_exchangelib_Downloader.py

支持明文和NTLM Hash的登录,代码支持以下功能:

  • 支持自己的Exchange服务器和Office365(outlook.office365.com)
  • download,下载邮件并提取附件,可指定邮箱文件夹和下载数量
  • search,邮件搜索并下载,支持关键词、时间、长度等语法
  • listfolder,枚举用户所有文件夹

在下载邮件时,以邮件用户名作为父文件夹,不同操作会创建不同的子文件夹,在使用搜索功能创建子文件夹时,为了避免特殊字符(例如字符>)无法作为文件夹名称,这里会去掉特殊字符

0x05 小结


本文介绍了exchangelib的用法,开源代码ewsManage_exchangelib_Downloader.py,实现了利用hash对Exchange资源的访问。

如果想要快速开发一个EWS的资源访问程序,推荐选择exchangelib


LEAVE A REPLY