Exchange Web Service(EWS)开发指南 - 嘶吼 RoarTalk – 网络安全行业综合服务平台,4hou.com

Exchange Web Service(EWS)开发指南

3gstudent 技术 2018-12-20 10:30:29
498451
收藏

导语:Exchange Web Service(EWS)提供了一个访问Exchange资源的接口,我在github没有找到很合适的参考项目,于是对这方面的内容做了一个系统性的整理,开源一份EWS的实现代码ewsManage,便于后续的二次开发。

0x00 前言

Exchange Web Service(EWS)提供了一个访问Exchange资源的接口,我在github没有找到很合适的参考项目,于是对这方面的内容做了一个系统性的整理,开源一份EWS的实现代码ewsManage,便于后续的二次开发。

0x01 简介

本文将要介绍以下内容:

· 使用EWS Managed API访问Exchange资源

· 使用EWS SOAP XML message访问Exchange资源

· 开源代码ewsManage

· ewsManage功能介绍

0x02 简介

官方文档:

https://docs.microsoft.com/en-us/exchange/client-developer/exchange-server-development

两种访问Exchange资源的方法:

· 使用EWS Managed API

· 使用EWS SOAP XML message

测试环境:

· Exchange Server 2013 SP1

· user: test1@test.com

· pwd: test123!

· url: https://test.com/ews/Exchange.asmx

· AutodiscoverUrl: test1@test.com

0x03 使用EWS Managed API

官方资料:

https://docs.microsoft.com/en-us/exchange/client-developer/exchange-web-services/get-started-with-ews-managed-api-client-applications

这里使用EWS Managed API 2.0

下载地址:

https://www.microsoft.com/en-us/download/details.aspx?id=35371

安装后从文件夹中找到文件Microsoft.Exchange.WebServices.dll和Microsoft.Exchange.WebServices.xml

注:如果已经获得这两个文件,不需要安装EwsManagedApi.msi,这两个文件可以在后面的开源工程ewsManage中找到。

(1)C Sharp实现

开发环境:VS2015

新建工程,并引用文件:

Microsoft.Exchange.WebServices.dll和Microsoft.Exchange.WebServices.xml

C Sharp代码示例(列出收件箱所有邮件的标题):

using System;
using Microsoft.Exchange.WebServices.Data;
using System.Net;
namespace EMAIL_EWS
{
    class Program
    {
        static void Main(string[] args)
        {
            ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => { return true; };
            ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2013_SP1);
            service.Credentials = new WebCredentials("test1", "test123!");
            service.AutodiscoverUrl("test1@test.com");
            ItemView view = new ItemView(int.MaxValue);
            FindItemsResults<Item> findResults = service.FindItems(WellKnownFolderName.Inbox, view);
            foreach (Item item in findResults.Items)
            {
                if (item.Subject != null)
                {
                    Console.WriteLine(item.Subject);
                }
                else
                {
                    Console.WriteLine("no Title\r\n");
                }
            }
        }
    }
}

(2)Powershell实现

Powershell代码示例(列出收件箱所有邮件的标题):

add-type @"
    using System.Net;
    using System.Security.Cryptography.X509Certificates;
    public class TrustAllCertsPolicy : ICertificatePolicy {
        public bool CheckValidationResult(
            ServicePoint srvPoint, X509Certificate certificate,
            WebRequest request, int certificateProblem) {
            return true;
        }
    }
"@
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
Import-Module -Name "C:\test\Microsoft.Exchange.WebServices.dll"
$Credentials = New-Object Microsoft.Exchange.WebServices.Data.WebCredentials("test1","test123!")
$exchService = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService
$exchService.Credentials = $Credentials
$exchService.AutodiscoverUrl("test1@test.com")
$exchService
$inbox = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($exchService,[Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox)
$inbox|gm
$ms = $inbox.FindItems(10) 
foreach ($m in $ms)
{
$m.Load()
$m.subject
}

注:Powershell同样需要Microsoft.Exchange.WebServices.dll

在程序开发中需要注意的细节如下:

1.Exchange Server的证书不可信

这会导致通过IE访问时显示证书不可信,需要点击Continue才能正常访问,如下图

Alt text

程序实现时会产生错误,提示如下:

The underlying connection was closed. Could not establish a secure SSL/TLS connection

可以通过添加证书信任策略避免这个问题:

using System.Net;
ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => { return true; };

2.Autodiscover自动发现服务

用来简化用户配置过程,具体到程序实现上对应ExchangeService.AutodiscoverUrl

参考地址:

https://msdn.microsoft.com/en-us/library/office/dd634273(v=exchg.80).aspx

输入邮箱地址,自动解析出Exchange Server Url

用法举例:

ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2013_SP1);
service.AutodiscoverUrl("test1@test.com", RedirectionUrlValidationCallback);

等价于

ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2013_SP1);
service.Url = new Uri("https://test.com/ews/Exchange.asmx");

注:实际使用时,如果Exchange Server关闭Autodiscover自动发现服务,可以选择指定Url。

3..NET Framework 4 and .NET Framework 3.5

.NET Framework 4为推荐开发环境。

Win7系统默认为.NET Framework 3.5,不支持.NET Framework 4

为了支持Win7,将工程指定为.NET Framework 3.5,不影响EWS Managed API的使用。

4.明文读取邮件的body属性

读取邮件的body属性时(也就是获得邮件的内容),默认输出格式为htlm。

想要获得邮件的内容,需要将输出格式改为Text。

解决方法:

https://stackoverflow.com/questions/11243911/ews-body-plain-text

5.搜索自定义文件夹时,指定深度搜索(遍历所有文件夹,包括更深的目录)

FindFoldersResults findResults = null;
FolderView view = new FolderView(int.MaxValue) { Traversal = FolderTraversal.Deep };

6.编译后仍需要依赖文件

编译后的程序在执行时,仍需要依赖文件Microsoft.Exchange.WebServices.dll(在同级目录)

0x04 使用EWS SOAP XML message

官方资料:

https://docs.microsoft.com/en-us/exchange/client-developer/exchange-web-services/get-started-with-ews-client-applications

EWS请求和响应使用SOAP(Simple Object Access Protocol)协议。

SOAP消息格式:

<SOAP-ENV:Envelope各种属性>
 <SOAP:HEADER>
 </SOAP:HEADER>
 <SOAP:Body>
 </SOAP:Body>
</SOAP-ENV:Envelope>

对应EWS的结构:

· Envelope元素(必须),作为SOAP消息的标志

· Header元素(可选),可用来指定ExchangeServer的版本

· Body元素(必须),包含所有的调用和响应信息

· Fault 元素(可选),包含错误消息

C Sharp代码示例(发送邮件):

using System;
using System.Net;
using System.IO;
using System.Text;
namespace EMAIL_EWS
{
    class Program
    {
        static void Main(string[] args)
        {
            String user = "test1";
            String password = "test123!";
            String readPath = ""
            ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => { return true; };          
            StreamReader sendData = new StreamReader("ews.xml", Encoding.Default);
            byte[] sendDataByte = Encoding.UTF8.GetBytes(sendData.ReadToEnd());
            sendData.Close();
            try
            {
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://test.com/ews/Exchange.asmx");
                request.Method = "POST";
                request.ContentType = "text/xml";
                request.ContentLength = sendDataByte.Length;
                request.AllowAutoRedirect = false;
                request.Credentials = new NetworkCredential(user, password);
                Stream requestStream = request.GetRequestStream();
                requestStream.Write(sendDataByte, 0, sendDataByte.Length);
                requestStream.Close();

                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                if (response.StatusCode != HttpStatusCode.OK)
                {
                    throw new WebException(response.StatusDescription);
                }
                Stream receiveStream = response.GetResponseStream();
                
                StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8);

                String receiveString = readStream.ReadToEnd();
                response.Close();
                readStream.Close();

                StreamWriter receiveData = new StreamWriter("out.xml");
                receiveData.Write(receiveString);                         
                receiveData.Close();                                        
            }
            catch (WebException e)
            {
                Console.WriteLine("[!]{0}", e.Message);
                Environment.Exit(0);
            }
            Console.WriteLine("[+]Done");
        }
    }
}

代码读取文件ems.xml的内容并进行发送,将结果保存为out.xml

ems.xml的内容为发送邮件:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
               xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" 
               xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" 
               xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <t:RequestServerVersion Version="Exchange2013_SP1" />
  </soap:Header>
  <soap:Body>
    <m:CreateItem MessageDisposition="SendAndSaveCopy">
      <m:SavedItemFolderId>
        <t:DistinguishedFolderId Id="sentitems" />
      </m:SavedItemFolderId>
      <m:Items>
        <t:Message>
          <t:Subject>This is Subject</t:Subject>
          <t:Body BodyType="HTML">This is Body</t:Body>
          <t:ToRecipients>
            <t:Mailbox>
              <t:EmailAddress>test1@test.com</t:EmailAddress>
              </t:Mailbox>
          </t:ToRecipients>
        </t:Message>
      </m:Items>
    </m:CreateItem>
  </soap:Body>
</soap:Envelope>

返回的内容(out.xml)如下图:

Alt text

ResponseCode为NoError,表示操作成功。

注:以上代码并不需要依赖文件Microsoft.Exchange.WebServices.dll

当然,如果需要使用Autodiscover自动发现服务,还是需要依赖文件Microsoft.Exchange.WebServices.dll

0x05 开源实现代码ewsManage

我将以上两种方法整合到一个工程,并添加了更多实用的功能,代码下载地址:

https://github.com/3gstudent/ewsManage

目前支持以下功能:

· 支持EWS Managed API和EWS SOAP

· 支持使用用户名口令或者使用当前凭据登录邮箱

· 支持是否忽略不可信证书

· 列出指定位置的邮件,包括附件中的文件名称和邮件内容 (对邮件内容长度做判断,如果大于100个字符,只显示前100个字符的内容)

· 列出指定位置的未读邮件,包括附件中的文件名称和邮件内容 (对邮件内容长度做判断,如果大于100个字符,只显示前100个字符的内容)

· 列出指定位置中的自定义文件夹(遍历所有子文件夹)

· 查看自定义文件下的所有邮件

· 查看自定义文件下的未读邮件

· 保存指定位置中的所有邮件(格式为eml)

· 保存指定邮件中的附件(指定ID)

· 向指定邮件添加附件(指定ID)

· 删除指定邮件的附件(指定ID)

· 删除指定邮件的所有附件

· 搜索带有指定关键词的邮件(常见位置,搜索标题名,附件名称和邮件正文)

· 删除指定邮件(指定ID)

· 查看某个邮件的具体内容(指定ID)

· 发送邮件(使用EWS SOAP)

· 读取xml文件,通过EWS SOAP发送命令

支持查询和操作的位置:

· 收件箱(Inbox)

· 草稿(Drafts)

· 已发送邮件(SentItems)

· 已删除邮件(DeletedItems)

· 发件箱(Outbox)

· 垃圾邮件(JunkEmail)

用法示例(1):

ewsManage.exe -CerValidation Yes -ExchangeVersion Exchange2013_SP1 -u test1 -p test123! -ewsPath https://test.com/ews/Exchange.asmx -Mode ListUnreadMail -Folder Inbox

使用证书验证,使用URL登录,查看收件箱的所有未读邮件,输出以下邮件信息:

· Subject

· HasAttachments

· ItemId

· DateTimeCreated

· DateTimeReceived

· DateTimeSent

· DisplayCc:

· DisplayTo

· InReplyTo:

· Size

· MessageBody(如果大于100个字符,只显示前100个字符的内容)

用法示例(2):

ewsManage.exe -CerValidation No -ExchangeVersion Exchange2013_SP1 -use the default credentials -AutodiscoverUrl test1@test.com -Mode ListMail -Folder SentItems

忽略证书验证,使用当前凭据自动登录,调用Autodiscover自动发现服务,查看所有已发送邮件的信息,输出的信息类别同(1)

注:可以配合mimikatz的Overpass-the-hash,实现通过hash登录Exchange

用法示例(3):

ewsManage.exe -CerValidation No -ExchangeVersion Exchange2013_SP1 -u test1 -p test123! -ewsPath https://test.com/ews/Exchange.asmx -Mode ListFolder -Folder Inbox

忽略证书验证,使用URL登录,查看收件箱中所有自定义文件夹的信息,输出以下信息:

· DisplayName

· Id

· TotalCount(该自定义文件夹下邮件的数量)

用法示例(4):

ewsManage.exe -CerValidation No -ExchangeVersion Exchange2013_SP1 -u test1 -p test123! -ewsPath https://test.com/ews/Exchange.asmx -Mode ListMailofFolder -Id AAMaADFlMjRjMdM2LTgxZTUtNGRmZC05ZDQyLTMzNDFlMzBmZWY1NwAzAAAAAAAR9UOK286vT6HjUgukBQGmAQBHzR2O8KNmTcffGwlY0A76AAAAADfqAAA=

查看指定自定义文件夹(通过Id筛选)中的所有邮件,输出的信息类别同(1)。

用法示例(5):

ewsManage.exe -CerValidation No -ExchangeVersion Exchange2013_SP1 -u test1 -p test123! -ewsPath https://test.com/ews/Exchange.asmx -Mode ExportMail -Folder Inbox

将收件箱的所有邮件保存为eml文件。

用法示例(6):

ewsManage.exe -CerValidation No -ExchangeVersion Exchange2013_SP1 -u test1 -p test123! -ewsPath https://test.com/ews/Exchange.asmx -Mode SaveAttachment -Id AAMzADFlMjRjMzM3LTgxZTUzNGRmZC25ZDQyLTMaNDFlMzBwZWY1NwBGAAAAAAAR8UOK236vT6HjUnujBQGmBwBHzR1O8KNmTrjfGwlY0A56AAAAAAEKAABHzR1O8KNmTrjfGzlY2A75AAAAABxFAAA=

保存指定邮件(通过Id筛选)中的附件,输出路径为当前路径。

用法示例(7):

ewsManage.exe -CerValidation No -ExchangeVersion Exchange2013_SP1 -u test1 -p test123! -ewsPath https://test.com/ews/Exchange.asmx -Mode AddAttachment -Id AAMzADFlMjRjMzM3LTgxZTUzNGRmZC25ZDQyLTMaNDFlMzBwZWY1NwBGAAAAAAAR8UOK236vT6HjUnujBQGmBwBHzR1O8KNmTrjfGwlY0A56AAAAAAEKAABHzR1O8KNmTrjfGzlY2A75AAAAABxFAAA= -AttachmentFile 1.txt

向指定邮件(通过Id筛选)添加附件,附件名称为1.txt。

用法示例(8):

ewsManage.exe -CerValidation No -ExchangeVersion Exchange2013_SP1 -u test1 -p test123! -ewsPath https://test.com/ews/Exchange.asmx -Mode DeleteAttachment -Id AAMzADFlMjRjMzM3LTgxZTUzNGRmZC25ZDQyLTMaNDFlMzBwZWY1NwBGAAAAAAAR8UOK236vT6HjUnujBQGmBwBHzR1O8KNmTrjfGwlY0A56AAAAAAEKAABHzR1O8KNmTrjfGzlY2A75AAAAABxFAAA= -AttachmentFile 1.txt

删除指定邮件(通过Id筛选)中的某个附件,附件名称为1.txt。

用法示例(9):

ewsManage.exe -CerValidation No -ExchangeVersion Exchange2013_SP1 -u test1 -p test123! -ewsPath https://test.com/ews/Exchange.asmx -Mode ClearAllAttachment -Id AAMzADFlMjRjMzM3LTgxZTUzNGRmZC25ZDQyLTMaNDFlMzBwZWY1NwBGAAAAAAAR8UOK236vT6HjUnujBQGmBwBHzR1O8KNmTrjfGwlY0A56AAAAAAEKAABHzR1O8KNmTrjfGzlY2A75AAAAABxFAAA=

删除指定邮件(通过Id筛选)中的所有附件。

用法示例(10):

ewsManage.exe -CerValidation No -ExchangeVersion Exchange2013_SP1 -u test1 -p test123! -ewsPath https://test.com/ews/Exchange.asmx -Mode SearchMail -String vpn

搜索带有指定关键词为vpn的邮件。

文件夹位置:

· 收件箱(Inbox)

· 草稿(Drafts)

· 已发送邮件(SentItems)

· 已删除邮件(DeletedItems)

· 发件箱(Outbox)

· 垃圾邮件(JunkEmail)

邮件位置:

· 标题名(Subject)

· 附件名称(AttachmentName)

· 邮件正文(Body)

用法示例(11):

ewsManage.exe -CerValidation No -ExchangeVersion Exchange2013_SP1 -u test1 -p test123! -ewsPath https://test.com/ews/Exchange.asmx -Mode DeleteMail -Id AAMzADFlMjRjMzM3LTgxZTUzNGRmZC25ZDQyLTMaNDFlMzBwZWY1NwBGAAAAAAAR8UOK236vT6HjUnujBQGmBwBHzR1O8KNmTrjfGwlY0A56AAAAAAEKAABHzR1O8KNmTrjfGzlY2A75AAAAABxFAAA=

完全删除指定邮件(通过Id筛选)。

用法示例(12):

ewsManage.exe -CerValidation No -ExchangeVersion Exchange2013_SP1 -u test1 -p test123! -ewsPath https://test.com/ews/Exchange.asmx -Mode ViewMail -Id AAMzADFlMjRjMzM3LTgxZTUzNGRmZC25ZDQyLTMaNDFlMzBwZWY1NwBGAAAAAAAR8UOK236vT6HjUnujBQGmBwBHzR1O8KNmTrjfGwlY0A56AAAAAAEKAABHzR1O8KNmTrjfGzlY2A75AAAAABxFAAA=

查看某个邮件的具体内容(指定ID),包括完整的正文内容。

用法示例(13):

ewsManage.exe -CerValidation No -ExchangeVersion Exchange2013_SP1 -u test1 -p test123! -ewsPath https://test.com/ews/Exchange.asmx -Mode ReadXML -Path ews.xml

读取ews.xml文件中的命令,通过EWS SOAP发送。

0x06 小结

本文介绍了两种访问Exchange资源的方法,开源工程ewsManage,便于后续的二次开发。

  • 分享至
取消

感谢您的支持,我会继续努力的!

扫码支持

打开微信扫一扫后点击右上角即可分享哟

发表评论

 
本站4hou.com,所使用的字体和图片文字等素材部分来源于原作者或互联网共享平台。如使用任何字体和图片文字有侵犯其版权所有方的,嘶吼将配合联系原作者核实,并做出删除处理。
©2022 北京嘶吼文化传媒有限公司 京ICP备16063439号-1 本站由 提供云计算服务