Good in study, attitude and health

Zimbra-SOAP-API开发指南5——邮件转发

0x00 前言


本文将要继续扩充开源代码Zimbra_SOAP_API_Manage的功能,通过Zimbra SOAP API修改配置实现邮件转发,分享开发细节。

0x01 简介


本文将要介绍以下内容:

  • 添加邮件转发
  • 查看邮件转发的配置
  • 查看文件夹共享的配置
  • 开源代码

0x02 添加邮件转发


Zimbra支持将收到的邮件额外转发至另一邮箱,通过Web界面的操作方法如下:

登录邮箱后,依次选择Preferences->Mail,如下图

Alt text

设置转发邮箱后,点击Save

如果想要转发多个邮箱,可以使用,进行分割,同时转发至两个邮箱的示例:test1@test.com,test2@test.com

接下来,通过抓包的方式分析实现流程,进而使用程序实现这部分功能

抓包获得的soap格式示例:

<soap:Body>
<BatchRequest xmlns="urn:zimbra" onerror="stop">
<ModifyPrefsRequest xmlns="urn:zimbraAccount" requestId="0">
<pref name="zimbraPrefMailForwardingAddress">test1@test.com</pref>
</ModifyPrefsRequest>
</BatchRequest>
</soap:Body>

实现代码示例:

def addforward_request(uri,token):
    print("[*] Input the mailbox to forward:")
    print("    Eg :test1@test.com,test2@@test.com")
    mailbox = input("[>]: ")
    request_body="""<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
       <soap:Header>
           <context xmlns="urn:zimbra">
               <authToken>{token}</authToken>
           </context>
       </soap:Header>
       <soap:Body>
            <BatchRequest xmlns="urn:zimbra" onerror="stop">
                <NoOpRequest xmlns="urn:zimbraMail" requestId="0"/>
                <ModifyPrefsRequest xmlns="urn:zimbraAccount" requestId="1">
                    <pref name="zimbraPrefMailForwardingAddress">{mailbox}</pref>
                </ModifyPrefsRequest>
            </BatchRequest>
       </soap:Body>
    </soap:Envelope>
    """
    try:
        r=requests.post(uri+"/service/soap",headers=headers,data=request_body.format(token=token,mailbox=mailbox),verify=False,timeout=15)
        if r.status_code == 200:
            print("[+] Add success")
        else:    
            print(r.status_code)
            print(r.text)        
        
    except Exception as e:
        print("[!] Error:%s"%(e))

对于清除邮件转发的设置,只需要将邮箱地址设置为空即可

0x03 查看邮件转发的配置


在我们添加邮件转发前,通常需要先获得邮箱转发的配置

通过抓包发现,在访问Web主页面时,如果存在邮件转发的设置,那么返回数据会增加以下内容:

"zimbraPrefMailForwardingAddress":"test@test.com"

如果不存在邮件转发的设置,返回数据不存在字符zimbraPrefMailForwardingAddress

在程序实现上,访问Web主页面需要添加Cookie,再通过正则表达式筛选出指定的内容即可

实现代码示例:

def getforward_request(uri,token):
    try:
        headers["Cookie"]="ZM_AUTH_TOKEN="+token+";"
        r=requests.get(uri,headers=headers,verify=False,timeout=15)
        if r.status_code == 200 and 'zimbraPrefMailForwardingAddress' in r.text:
            print("[+] Forward")
            pattern_name = re.compile(r"\"zimbraPrefMailForwardingAddress\":\"(.*?)\"")
            name = pattern_name.findall(r.text)
            print("    " + name[0])
        else:           
            print(r.status_code)
            print("[-] No Forward")
        
    except Exception as e:
        print("[!] Error:%s"%(e))

0x04 查看文件夹共享的配置


在上篇文章《Zimbra-SOAP-API开发指南4——邮件导出和文件夹共享》缺少了查看文件夹共享配置的方法,本文作为补充

通过抓包进行分析

发送的url示例: https://<url>/service/soap/BatchRequest

发送的内容示例:

{"Header":{"context":{"_jsns":"urn:zimbra","userAgent":{"name":"ZimbraWebClient - GC103 (Win)","version":"8.8.12_GA_3844"},"session":{"_content":123,"id":123},"account":{"_content":"admin@test.com","by":"name"},"csrfToken":"0_71c4fc5d29c57ec1863d1630a77bb4834f0cd67c"}},"Body":{"BatchRequest":{"_jsns":"urn:zimbra","onerror":"continue","GetFolderRequest":[{"_jsns":"urn:zimbraMail","folder":{"l":"2"},"requestId":0}]}}}

返回的内容示例:

{"Header":{"context":{"session":{"id":"123","_content":"123"},"change":{"token":151},"_jsns":"urn:zimbra"}},"Body":{"BatchResponse":{"GetFolderResponse":[{"folder":[{"id":"2","uuid":"68dd08c1-26ea-4460-9716-14eee9103a45","deletable":false,"name":"Inbox","absFolderPath":"/Inbox","l":"1","luuid":"0e366bb5-f76c-40ce-9a92-28def5720d67","f":"ui","u":14,"view":"message","rev":1,"ms":147,"webOfflineSyncDays":30,"activesyncdisabled":false,"n":14,"s":24088,"i4ms":112,"i4next":273,"acl":{"grant":[{"zid":"f87692f9-0ab9-441d-9870-ef5b6dd6f375","gt":"usr","perm":"r","d":"test1@test.com"}]}}],"requestId":"0","_jsns":"urn:zimbraMail"}],"_jsns":"urn:zimbra"}},"_jsns":"urn:zimbraSoap"}

从以上内容可以知道,相关的请求为GetFolderRequest

查看GetFolderRequest的用法:https://files.zimbra.com/docs/soap_api/8.8.15/api-reference/zimbraMail/GetFolder.html

经过前期的积累,这里也可以通过Zimbra SOAP API实现,发送GetFolderRequest,对返回内容进行筛选即可

收件箱存在文件共享的数据内容示例:

<folder i4ms="201"rev="1" i4next="282" f="ui" ms="147" deletable="0" l="1" uuid="68dd08c1-26ea-4460-9716-14eee9103a45" n="16" luuid="0e366bb5-f76c-40ce-9a92-28def5720d67" activesyncdisabled="0" absFolderPath="/Inbox" view="message" s="29224" u="16" name="Inbox" id="2" webOfflineSyncDays="30"><acl><grant zid="f87692f9-0ab9-441d-9870-ef5b6dd6f375" perm="r" d="test1@test.com" gt="usr"/></acl></folder>

在程序实现上,如果返回结果中存在字符<acl>,代表存在文件共享,提取出对应的数据即可

实现代码示例:

def getshare_request(uri,token):
    request_body="""<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
       <soap:Header>
           <context xmlns="urn:zimbra">
               <authToken>{token}</authToken>
           </context>
       </soap:Header>
       <soap:Body>
         <GetFolderRequest xmlns="urn:zimbraMail"> 
         </GetFolderRequest>
       </soap:Body>
    </soap:Envelope>
    """
    try:
        r=requests.post(uri+"/service/soap",headers=headers,data=request_body.format(token=token),verify=False,timeout=15)
        if r.status_code == 200 and '<acl>' in r.text:
            print("[+] Folder Share")
            pattern_name = re.compile(r"<folder(.*?)</folder>")
            folders = pattern_name.findall(r.text)
            for i in range(len(folders)):
                if '<acl>' in folders[i]:
                    pattern_name = re.compile(r"name=\"(.*?)\"")
                    name = pattern_name.findall(folders[i])
                    pattern_name = re.compile(r"<acl>(.*?)</acl>")
                    acl = pattern_name.findall(r.text)
                    print("    " + name[len(name)-1] + ":")
                    print("    " + acl[0])
        else:
            print(r.status_code)
            print(r.text)
            print("[-] No Folder Share")        
        
    except Exception as e:
        print("[!] Error:%s"%(e))

返回结果示例:

Inbox:
<grant zid="f87692f9-0ab9-441d-9870-ef5b6dd6f375" perm="rwidx" d="test1@test.com" gt="usr"/>

在删除文件夹共享的操作时,需要填入zidInbox对应的数字2即可

0x05 开源代码


新的代码已上传至github,地址如下:

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

添加以下四个功能:

  • AddForward:添加邮件转发
  • GetForward:查看邮件转发
  • GetShare:查看文件夹共享
  • RemoveForward:清除邮件转发的设置

0x05 小结


本文扩充了Zimbra SOAP API的调用方法,添加四个实用功能,实现方法和思路也可在XSS漏洞上进行测试。


LEAVE A REPLY