Research Notes on How MoveIt Works (CVE-2023-34362)

by | Aug 17, 2023 | Ridge Security

In this blog post, the Ridge Security research team shares an in-depth analysis of MoveIt (CVE-2023-34362), providing a unique understanding of this critical vulnerability from an attacker’s perspective. This forms the foundation for the development of RidgeBot’s plugins, which will effectively detect and validate this vulnerability for our customers’ organizations in the upcoming software release.

Progress MOVEit is the leading secure Managed File Transfer (MFT) software used by thousands of organizations around the world to provide complete visibility and control over file transfer activities. On May 31st, 2023, Progress Software disclosed that there was a critical SQLI vulnerability (CVE-2023-34362) in Progress MOVEit Transfer before 2021.0.6 (13.0.6), 2021.1.4 (13.1.4), 2022.0.4 (14.0.4), 2022.1.5 (14.1.5), and 2023.0.1 (15.0.1).

The SQLI vulnerability resides in the MOVEit.DMZ.ClassLib.dll!MOVEit.DMZ.ClassLib.UserEngine.UserGetUsersWithEmailAddress method, the following is the code snippet decompiled by Il spy:

From the first glance, it seems both InstID and EmailAddress are not properly sanitized, but if we examine all the cross reference to the function, we would realize that it appears that we can’t control the InstID variable. But we have full control of the EmailAddress variable.

However, the vulnerability is not reachable directly from non-localhost. It turns out that there was another vulnerability in the moveitisapi.dll module when processing the m2 action, the following is the key code snippet:

We can see that if the value of http header X-siLock-Transaction is “folder_add_by_path”, then the request will be forwarded to the machine2 url (the default value is https//<moveit server>/machine2.aspx). The implementation of the function GetHeaderByName has a prototype as follows:

bool  GetHeaderByName(std::string *data, const char *header_name, char *out_header_value, int out_header_value_len);

The implementation of the function is as follows:

From the code we can see that It doesn’t actually parse the http header, instead it simply searches for the http header name within the given input data to locate the header, “X-siLock-Transaction:” in our case. It is worth noting that the search is case insensitive. The header extraction is problematic because it allows the attackers to forge a header without any difficulty.

When an attacker sends a request to the MOVEIT server:

GET /moveitisapi/moveitisapi.dll?action=m2 HTTP/1.1Host: 192.168.200.218User-Agent: python-requests/2.28.1Accept-Encoding: gzip, deflateAccept: */*Connection: keep-aliveX-siLock-sth=XX-siLock-Transaction: folder_add_by_path X-siLock-Transaction=session_setvarsX-siLock-SessVar=MyPermission: 1000  

The string in red will be interpreted as a http header “X-siLock-Transaction: folder_add_by_path”, and the request will be redirected to machine 2 URL. 

This bug plays a critical role in the exploit chain, because it effectively prevents ISAPI from combining the the header values that share the same names. 

The last two headers of the request have a magic power, when machine2.aspx receives them, it will set the session variable as instructed:

The function has been removed in the official patch for the vulnerability. 

As aforementioned, the EmailAddress is the point where we can inject malicious payload. However, there is no good way for us to trigger the function MOVEit.DMZ.ClassLib.dll!MOVEit.DMZ.ClassLib.UserEngine.UserGetUsersWithEmailAddress with an EmailAddress controlled by us. We need to leverage the second bug to set the ” SelfProvisionedRecips” to the malicious payload.

Then later we can send a crafted request to the guestaccess.aspx endpoint, and trigger the MOVEit.DMZ.ClassLib.SILGuestPackageInfo.LoadFromSession method: 

The SelfProvisionedRecips member later will be used by MOVEit.DMZ.ClassLib.MsgEngine.MsgPostForGuest:

We can see the PkgInfo.SelfProvisionedRecips will be split by ‘,’ and then fed into the function UserGetSelfProvisionUserRecipsWithEmailAddress, which passes the the email address as it is to the vulnerable function UserGetUsersWithEmailAddress. By exploiting the vulnerability, attackers can exfiltrate confidential information or even achieve arbitrary code execution. It is believed that the vulnerability has been actively used by the cl0p ransomware gang since May 27, 2023.