0x00 Preface

---

In previous articles, 'Exchange Web Service (EWS) Development Guide 4 – Auto Downloader' and 'Exchange Web Service (EWS) Development Guide 5 – exchangelib', two methods for accessing Exchange resources using hash were introduced, each with its own characteristics.

The former employs a lower-level communication protocol, which is relatively cumbersome in terms of functionality implementation but helps in understanding the principles of communication protocols and vulnerability exploitation. The latter leverages the third-party library exchangelib, making development convenient but less suitable for vulnerability exploitation.

From the perspective of vulnerability exploitation, using only third-party packages that encapsulate NTLM authentication neither affects vulnerability exploitation nor compromises efficiency.

Therefore, this article selects the third-party package requests_ntlm, taking automated email downloading and attachment extraction as examples, to introduce its usage with open-source code.

0x01 Introduction

---

This article will cover the following topics:

  • Usage of requests_ntlm
  • Development details
  • Open-source code

0x02 Usage of requests_ntlm

---

Documentation:

https://github.com/requests/requests-ntlm

1. Two Authentication Methods

I found the method for Hash-based authentication in requests_ntlm.py versions below 1.0.0, at the code location:

https://github.com/requests/requests-ntlm/blob/v0.3.0/requests_ntlm/requests_ntlm.py#L16

Here you can find the parameter format for Hash-based authentication as ABCDABCDABCDABCD:ABCDABCDABCDABCD

Example code for two methods to authenticate with Exchange is as follows:

(1) Plaintext Authentication

target = "192.168.1.1"
username = "[email protected]"
password = "password1"
res = requests.post("https://" + target + "/ews/exchange.asmx", data=POST_BODY, headers=headers, verify=False, auth=HttpNtlmAuth(username, password))
print(res.status_code)
print(res.text)

(2) Hash Authentication

target = "192.168.1.1"
username = "[email protected]"
hash = "00000000000000000000000000000000:5835048CE94AD0564E29A924A03510EF"
res = requests.post("https://" + target + "/ews/exchange.asmx", data=POST_BODY, headers=headers, verify=False, auth=HttpNtlmAuth(username, hash))
print(res.status_code)
print(res.text)

2. Session Mechanism

requests_ntlm supports the Session mechanism, which reduces the number of authentication attempts, shortens communication packets, and improves efficiency.

0x03 Development Details

---

1. Reimplement ewsManage_Downloader.py using requests_ntlm

Based on the original script ewsManage_Downloader.py, only the following replacements are needed.

(1)

Original code:

status, responsetext = ntlm_auth_login(host, port, mode, domain, user, data, POST_BODY)

Replace with:

res = requests.post("https://" + host + "/ews/exchange.asmx", data=POST_BODY, headers=headers, verify=False, auth=HttpNtlmAuth(user, data))

(2)

Original code:

status

Replace with:

res.status_code

(3)

Original code:

if res.status_code == "200" and "NoError" in responsetext:

Replace with:

if res.status_code == 200 and "NoError" in res.text:

(4)

Original code:

host, port, mode, domain, user, data

Replace with:

host, mode, user, data

(5)

Original code:

responsetext

Replace with:

res.text

(6)

Original code:

sys.argv[1], int(sys.argv[2]), sys.argv[3], sys.argv[4], sys.argv[5], sys.argv[6]

Replace with:

sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4]

(7)

Original code:

path1 + '\\' + sys.argv[5]

Replace with:

path1 + '\\' + sys.argv[3]

Finally, remove some redundant code

The complete code has been uploaded to GitHub, address as follows:

An open-source project

2. Reimplement ewsManage_Downloader.py using Session mechanism

Using Session mechanism can reduce the number of authentication attempts, shorten communication packets, and improve efficiency

Therefore, reimplement ewsManage_Downloader.py using Session mechanism here

Example of switching to Session mechanism:

Original code:

target = "192.168.1.1"
username = "[email protected]"
password = "password1"
res = requests.post("https://" + target + "/ews/exchange.asmx", data=POST_BODY, headers=headers, verify=False, auth=HttpNtlmAuth(username, password))
print(res.status_code)
print(res.text)
res = requests.post("https://" + target + "/ews/exchange.asmx", data=POST_BODY2, headers=headers, verify=False, auth=HttpNtlmAuth(username, password))
print(res.status_code)
print(res.text)

New code:

target = "192.168.1.1"
username = "[email protected]"
password = "password1"
session = requests.Session()
session.auth = HttpNtlmAuth(username, password)
res = session.post("https://" + target + "/ews/exchange.asmx", data=POST_BODY, headers=headers, verify=False)
print(res.status_code)
print(res.text)
res = session.post("https://" + target + "/ews/exchange.asmx", data=POST_BODY2, headers=headers, verify=False)
print(res.status_code)
print(res.text)

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

An open-source project

0x04 Summary

---

In Exchange Web Service (EWS) development, using the third-party package requests_ntlm, which encapsulates the NTLM authentication process, not only improves development efficiency but also does not affect the writing of exploit code. Moreover, it can leverage the Session mechanism to reduce communication data during authentication, making it highly recommended.