Penetration Basics - Zimbra Version Detection

Onedaysec
4 min read
3 views
Penetration Basics - Zimbra Version Detection — One Day Sec default thumbnail

0x00 Preface

---

This article will introduce multiple methods for detecting Zimbra versions, implement automation through Python, document development details, and provide open-source code.

0x01 Introduction

---

This article will cover the following:

  • Implementation Approach
  • Implementation Details
  • Open-Source Code

0x02 Implementation Approach

---

There are many methods to check the Zimbra version, each with its own advantages and disadvantages. The specific methods are as follows:

1. Via the Web Management Page

Access the 7071 management page through a browser, where the current Zimbra version is displayed on the main page.

For example, my test environment displays as:

Zimbra Version: 9.0.0_GA_4273.NETWORK

The version obtained through this method is the accurate version

2. By executing the commands

su zimbra
/opt/zimbra/bin/zmcontrol -v

For example, my test environment displays as:

Release 9.0.0.GA.3924.UBUNTU16.64 UBUNTU16_64 NETWORK edition, Patch 9.0.0_P24.1.

For the output results, note the following issues:

  • Release 9.0.0.GA.3924 corresponds to the initial installation package version and does not change with patch updates
  • Patch 9.0.0_P24.1 is the patch version, which changes when upgrading

Note:

For Zimbra patch updates, refer to:

https://wiki.zimbra.com/wiki/Zimbra_Releases/9.0.0/patch_installation

3. Via Zimbra SOAP API

Under default configuration, the zimbraSoapExposeVersion attribute is set to FALSE. Query command:

zmprov gs `hostname` | grep ExposeVersion

Return result:

zimbraImapExposeVersionOnBanner: FALSE
zimbraLmtpExposeVersionOnBanner: FALSE
zimbraPop3ExposeVersionOnBanner: FALSE
zimbraReverseProxyImapExposeVersionOnBanner: FALSE
zimbraReverseProxyPop3ExposeVersionOnBanner: FALSE
zimbraSoapExposeVersion: FALSE

After setting the zimbraSoapExposeVersion attribute to TRUE, the version can be obtained via Zimbra SOAP API. Command to modify the attribute:

su zimbra
/opt/zimbra/bin/zmprov mcf zimbraSoapExposeVersion TRUE

Example SOAP request format:




{token}






Return result under default configuration:

soap:Senderpermission denied: Version info is not available.service.PERM_DENIEDqtp2008966511-673279:1675321733266:bb7c9a24ece078fe

Return result after enabling zimbraSoapExposeVersion:

The version obtained through this method is the accurate version

4. Via IMAP protocol

Require Zimbra to open port 143

Command execution example:

nc 192.168.1.1 143
A001 ID NIL

Return result:

* ID ("NAME" "Zimbra" "VERSION" "9.0.0_GA_4273" "RELEASE" "20220506180442")

The version obtained through this method is the accurate version

5. Via IMAP over SSL protocol

Require Zimbra to open port 993

Command execution example:

openssl s_client -connect 192.168.1.1:993
show id ("a" "a")

Return result:

* ID ("NAME" "Zimbra" "VERSION" "9.0.0_GA_4273" "RELEASE" "20220506180442")

The version obtained through this method is the accurate version

6. Via specific URL

The specific URL contains installation information

Note:

This URL is not unique

Example access location: https://192.168.1.1/js/zimbraMail/share/model/ZmSettings.js

Example return result:

this.registerSetting("CLIENT_DATETIME", {type:ZmSetting.T_CONFIG, defaultValue:"20220324-0623"});
this.registerSetting("CLIENT_RELEASE", {type:ZmSetting.T_CONFIG, defaultValue:"20220324053424"});
this.registerSetting("CLIENT_VERSION", {type:ZmSetting.T_CONFIG, defaultValue:"9.0.0_GA_4258"});

CLIENT_DATETIME and CLIENT_RELEASE are consistent with the creation time of this file. The version obtained through this method is for reference only and cannot be used as an accurate basis for version detection

0x03 Implementation Details

---

Integrating the above detection methods, to adapt to various environments, the program implementation selects three methods: via IMAP protocol, via IMAP over SSL protocol, and via specific URL

1. Via IMAP protocol

Complete example code:

def getversionimap(ip):
try:
print("[*] Try to connect: " + ip + ":143")
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.settimeout(5)
s.connect((ip, 143))
s.sendall(''.encode())
response = s.recv(1024)
if "OK" in response.decode('UTF-8'):
print(" OK")
else:
print(response.decode('UTF-8'))
s.close()
sys.exit(0)
s.sendall('A001 ID NIL\r\n'.encode())
response = s.recv(1024)
if "Zimbra" in response.decode('UTF-8'):
versiondata=re.compile(r"VERSION\" \"(.*?)\"")
version = versiondata.findall(response.decode('UTF-8'))[0]

releasedata=re.compile(r"RELEASE\" \"(.*?)\"")
release = releasedata.findall(response.decode('UTF-8'))[0]
print("[+] Version: " + version)
print(" Release: " + release)
return release
else:
print(response.decode('UTF-8'))
s.close()
except Exception as e:
print(e)
return ""

2. Via IMAP over SSL protocol

Need to convert IP to hostname as parameter, example code:

hostname = socket.gethostbyaddr(ip)
print(hostname[0])

Complete example code:

def getversionimapoverssl(ip):
try:
hostname = socket.gethostbyaddr(ip)
print("[*] Try to connect: " + hostname[0] + ":993")
context = ssl.create_default_context()
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s = context.wrap_socket(s, server_hostname=hostname[0])
s.settimeout(5)
s.connect((ip, 993))
s.sendall(''.encode())
response = s.recv(1024)
if "OK" in response.decode('UTF-8'):
print(" Success")
else:
print(response.decode('UTF-8'))
s.close()
sys.exit(0)
s.sendall('A001 ID NIL\r\n'.encode())
response = s.recv(1024)
if "Zimbra" in response.decode('UTF-8'):
versiondata=re.compile(r"VERSION\" \"(.*?)\"")
version = versiondata.findall(response.decode('UTF-8'))[0]

releasedata=re.compile(r"RELEASE\" \"(.*?)\"")
release = releasedata.findall(response.decode('UTF-8'))[0]
print("[+] Version: " + version)
print(" Release: " + release)
return release
else:
print(response.decode('UTF-8'))
s.close()
except Exception as e:
print(e)
return ""

Some environments cannot resolve IP to hostname, causing error: [Errno 11004] host not found. Therefore, the program logic prioritizes using the IMAP protocol.

3. Via specific URL

Complete example code:

def getversionweb(ip):
try:
url = "https://" + ip + "/js/zimbraMail/share/model/ZmSettings.js"
print("[*] Try to access: " + url)
headers={
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36",
}
response = requests.get(url, headers=headers, verify=False, timeout=5)

if response.status_code == 200 and 'CLIENT_RELEASE' in response.text:
print(" Success")
VERSION_name = re.compile(r"CLIENT_VERSION\", {type:ZmSetting.T_CONFIG, defaultValue:\"(.*?)\"}\);")
CLIENT_VERSION = VERSION_name.findall(response.text)

RELEASE_name = re.compile(r"CLIENT_RELEASE\", {type:ZmSetting.T_CONFIG, defaultValue:\"(.*?)\"}\);")
CLIENT_RELEASE = RELEASE_name.findall(response.text)

print("[+] Version: " + CLIENT_VERSION[0])
print(" Release: " + CLIENT_RELEASE[0])
else:
print("[-]")
print(response.status_code)
print(response.text)
except Exception as e:
print(e)

0x04 Open Source Code

---

The complete implementation code has been uploaded to GitHub at the following address:

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

The code first attempts to obtain version information through a specific URL, then reads version information via the IMAP protocol. If that fails, it finally reads version information via IMAP over SSL protocol.

0x05 Summary

---

This article introduces multiple methods for Zimbra version detection, compares their advantages and disadvantages, selects effective methods and implements automation through Python, records development details, and open-sources the code as an excellent learning example.

Related Questions & Answers

How does the open-source implementation prioritize different detection methods, and why is IMAP preferred over IMAP over SSL?

The implementation first attempts the URL method, then IMAP (port 143), and finally IMAP over SSL (port 993). IMAP is preferred over SSL because SSL requires resolving the IP to a hostname via reverse DNS, which may fail in some environments (e.g., `[Errno 11004] host not found`). IMAP works without hostname resolution and still provides accurate version info. For full code, refer to the GitHub repository linked in the article [Penetration Basics - Zimbra Version Detection](/news/penetration-basics-zimbra-version-detection1).

What is the limitation of using the specific URL (`/js/zimbraMail/share/model/ZmSettings.js`) for version detection?

The URL provides `CLIENT_VERSION` and `CLIENT_RELEASE` values, but these are derived from the client-side build timestamp and may not reflect the exact server patch level. The article states this method is for reference only and cannot be used as an accurate basis for version detection. It should be used as a supplement to more reliable methods like IMAP or SOAP. For other accurate methods, see [Penetration Basics - Zimbra Version Detection](/news/penetration-basics-zimbra-version-detection1).

Why is the version obtained from the IMAP protocol considered accurate, and how do you extract it?

The IMAP protocol (port 143) returns a response including fields like `VERSION` and `RELEASE` from the `ID` command, which directly corresponds to the installed Zimbra version and patch level. For example, sending `A001 ID NIL` and parsing the response yields accurate version info like `9.0.0_GA_4273`. This method is reliable and often used in automated detection scripts similar to those described in [Penetration Basics - Zimbra Version Detection](/news/penetration-basics-zimbra-version-detection1).

What are the different methods to detect a Zimbra version during penetration testing?

There are several methods, including accessing the web management page on port 7071, running `su zimbra /opt/zimbra/bin/zmcontrol -v` on the server, querying the SOAP API (if `zimbraSoapExposeVersion` is enabled), connecting via IMAP on port 143 or IMAP over SSL on port 993, and checking a specific JavaScript URL like `/js/zimbraMail/share/model/ZmSettings.js`. For details, see the full article [Penetration Basics - Zimbra Version Detection](/news/penetration-basics-zimbra-version-detection1).

Continue Reading