0x00 Preface

---

Exchange has numerous versions and a large number of historical vulnerabilities, making it necessary to implement version detection and vulnerability scanning through programs. This article will introduce two methods for version detection using Python, detail the implementation of vulnerability scanning, and provide open-source code.

0x01 Introduction

---

This article will cover the following:

  • Implementation Approach
  • Implementation Details
  • Open-Source Code

0x02 Implementation Approach

---

1. Version Identification

(1) Obtain the Exact Version (Build Number)

Access the EWS interface; the exact version can be obtained from the X-OWA-Version in the Response Headers, as shown in the figure below

Alt text

Advantage: Precise version (Build number) can correspond to specific release dates

Disadvantage: The method is not universal; some older Exchange versions are not supported

(2) Obtain approximate version

Access the OWA interface; the approximate version can be obtained from the echoed content, as shown in the figure below

Alt text

Advantage: The method is universal

Disadvantage: The approximate version cannot correspond to an exact release date, only to a range

In summary, for version identification, first attempt to obtain the precise version; if that fails, then attempt to obtain the approximate version

After obtaining the version number, you can query the corresponding Exchange version and release date on the official website. Query address: https://docs.microsoft.com/en-us/exchange/new-features/build-numbers-and-release-dates?view=exchserver-2019

2. Vulnerability Detection

Details of Exchange vulnerabilities can be viewed by accessing https://msrc.microsoft.com/update-guide/vulnerability/, for example:

URL for CVE-2020-0688: https://msrc.microsoft.com/update-guide/vulnerability/CVE-2020-0688

For vulnerability detection, the patch date can be used as a criterion. If the identified Exchange version's release date is earlier than a certain patch date, then it is determined that the Exchange is vulnerable to the vulnerability described in that patch.

0x03 Implementation Details

---

1. Version Identification

Implementation code for obtaining version by accessing EWS interface:

url1 = "https://" + host + "/ews"
req = requests.get(url1, headers = headers, verify=False)
if "X-OWA-Version" in req.headers:
version = req.headers["X-OWA-Version"]
print(version)

Implementation code for obtaining version by accessing OWA interface:

url2 = "https://" + host + "/owa"
req = requests.get(url2, headers = headers, verify=False)
pattern_version = re.compile(r"/owa/auth/(.*?)/themes/resources/favicon.ico")
version = pattern_version.findall(req.text)[0]
print(version)

After obtaining the version number, it needs to be matched against known version information. To improve efficiency, you can choose to store known version information in a list, with elements including Exchange version, release date, and build number

First, copy known version information from the official website, then store the version information in a list via string replacement.

During version matching, it is necessary to distinguish between exact versions and approximate versions. Exact versions can correspond to a unique result, while approximate versions require filtering out all possible results.

Build number format example: 15.1.2375.24

Approximate version format example: 15.1.2375

Approximate version filtering method:

Truncate the Build number string by removing the data after the last character ".", then compare it with the approximate version and output all results.

Code example:

versionarray = [
["Exchange Server 2019 CU11 Mar22SU", "March 8, 2022", "15.2.986.22"],
["Exchange Server 2019 CU11 Jan22SU", "January 11, 2022", "15.2.986.15"],
["Exchange Server 2019 CU11 Nov21SU", "November 9, 2021", "15.2.986.14"],
["Exchange Server 2019 CU11 Oct21SU", "October 12, 2021", "15.2.986.9"],
["Exchange Server 2019 CU11", "September 28, 2021", "15.2.986.5"],
["Exchange Server 2019 CU10 Mar22SU", "March 8, 2022", "15.2.922.27"]
]
version="15.2.986"
for value in versionarray:
if version in value[2][:value[2].rfind(".")]:
print("[+] Version: " + value[2])
print(" Product: " + value[0])
print(" Date: " + value[1])

2. Vulnerability Detection

Using patch time as the basis for judgment, and similarly to improve efficiency, storing known vulnerability information in a list, with elements including release date and vulnerability number

To facilitate time comparison, it is necessary to change the time format, for example, modifying September 28, 2021 to 09/28/2021

Code example:

vularray = [
["CVE-2020-0688", "02/11/2020"],
["CVE-2021-26855+CVE-2021-27065", "03/02/2021"],
["CVE-2021-28482", "04/13/2021"]
]
date="03/01/2021"
for value in vularray:
if (date.split('/')[2] < value[1].split('/')[2]):
print("[+] " + value[0] + ", " + value[1])
else:
if (date.split('/')[2] == value[1].split('/')[2]) & (date.split('/')[0] < value[1].split('/')[0]):
print("[+] " + value[0] + ", " + value[1])
else:
if (date.split('/')[2] == value[1].split('/')[2]) & (date.split('/')[0] == value[1].split('/')[0]) & (date.split('/')[1] < value[1].split('/')[1]):
print("[+] " + value[0] + ", " + value[1])

0x04 Open Source Code

---

Due to the length of the code content, the complete implementation code has been uploaded to GitHub at the following address:

An open-source project

The version database date is 03/21/2022

Vulnerability information includes the following identifiers:

  • CVE-2020-0688
  • CVE-2021-26855+CVE-2021-27065
  • CVE-2021-28482
  • CVE-2021-34473+CVE-2021-34523+CVE-2021-31207
  • CVE-2021-31195+CVE-2021-31196
  • CVE-2021-31206
  • CVE-2021-42321

The code can automatically identify the exact version; if identification fails, it switches to identifying the approximate version and marks all matching vulnerabilities.

0x05 Summary

---

This article introduces two methods for Exchange version detection using Python, detailing their implementation, providing open-source code, and serving as an excellent learning example.