Skip to content
Rapid7 Analysis: CVE-2023

Rapid7 Analysis: CVE-2023

Rapid7 June 17, 2026

On September 27, 2023, Progress Software disclosed CVE-2023-40044, a .NET deserialization vulnerability affecting the Ad Hoc Transfer module of WS_FTP Server, a secure file transfer product. The vulnerability, which was originally discovered by Assetnote, is trivially exploitable and allows an unauthenticated attacker to achieve RCE on the target system.

NIST have assigned a CVSS base score of 8.8 , whilst Progress Software have assigned a CVSS base score of 10. The difference in these two scores arises from NIST’s determination that the privileges required (PR) for exploitation are low instead of non-existent (i.e., that an attacker must already possess some level of existing privilege in order to carry out an attack). We did not observe this requirement during our analysis of the vulnerability — we verified that an attacker can exploit CVE-2023-40044 fully unauthenticated. We believe the correct scoring for this vulnerability would be 9.8 .

The following versions of the software are affected if the Ad Hoc Transfer module is enabled:

We installed an older version of WS_FTP Server (2020.0.1) and the patched version of the software (2022.0.2). As the advisory notes, the vulnerable component is in the Ad Hoc Transfer (AHT) module, which is installed by default. This is a .NET module that runs in a Microsoft Internet Information Server (IIS) instance, and is accessible by default over HTTPS on port 443. The binaries are located in the C:\Program Files (x86)\Progress\WS_FTP Server\Ad Hoc Transfer\AHT\Bin folder. Decompiling all the binaries to .NET source code via the dotPeek tool, we can begin to inspect them using a diffing tool BeyondCompare. We identified a suspicious change in the class FileUploadLibrary.dll!MyFileUpload.FormStream, as shown below.

We can see the CheckForActionFields method has been changed to remove a suspicious call to UploadManager.Instance.DeserializeProcessor. Inspecting MyFileUpload.UploadManager.DeserializeProcessor, we can see the entire functionality has been removed in the latest version of the software.

Of note is the use of the unsafe deserialization method BinaryFormatter.Deserialize, which is known to be exploitable if an attacker can provide arbitrary attacker-controlled data.

The CheckForActionFields method tries to extract an HTTP multipart form field that begins with a tag value ::AHT_DEFAULT_UPLOAD_PARAMETER::. The data after this tag value is then deserialized via UploadManager.DeserializeProcessor. We can also note that using a tag value of ::AHT_UPLOAD_PARAMETER:: will also reach the same unsafe deserialization code path.

To reach the CheckForActionFields method, we must be able to call the method MyFileUpload.FormStream.ProcessField, which is called by FormStream.Write. The Write method will iterate over the HTTP form data, by first searching for the form data’s boundary string, then the headers for that field are parsed via ParseHeader. Notably the member variable this._inField will be set to true. This will later allow us to call ProcessField. After the headers are parsed, if they do not contain the header values filename and Content-Disposition, then the member variable this._inFile will be set to false. This is important — as we can note from the ProcessField source code above, we can only call CheckForActionFields if _inFile is false.

The Write method will be called by UploadModule.Context_AcquireRequestState. The module MyFileUpload.UploadModule contains an IIS event handler which will call Context_AcquireRequestState when a new HTTPS request is processed.

Examining the file C:\Program Files (x86)\Progress\WS_FTP Server\Ad Hoc Transfer\AHT\web.config, which is responsible for configuring the WS_FTP Ad-Hoc Transfer application in IIS, we can see the module MyFileUpload.UploadModule is loaded into IIS.

We can now speculate that the module UploadModule will pre-process all incoming HTTP(S) requests that are trying to upload a file. If we can specify a malicious HTTP form field with an expected tag string of either ::AHT_DEFAULT_UPLOAD_PARAMETER:: or ::AHT_UPLOAD_PARAMETER::, we will be able to deserialize an arbitrary .NET object and achieve unauthenticated RCE.

We can exploit this vulnerability with a single HTTPS POST request to any URI in the Ad Hoc Transfer module. These URI’s begin with the path /AHT/. We generate a suitable .NET deserialization gadget with the tool ysoserial.net as follows. Note, we choose notepad.exe as the gadget’s command to execute during deserialization.

The POST request we want to send will look as follows:

We can easily script this with some Ruby.

And run it against our target system.

Finally, we can observe that we have spawned the notepad.exe application as a child of the IIS worker process w3wp.exe, and with the user account NT AUTHORITY\NETWORK SERVICE.

As the vulnerable application runs as an IIS module, we can inspect the IIS logs. An example of a successful exploitation attempt is shown below.

We can note the presence of a POST request to a path that begins with /AHT/.

To remediate this issue, you should update to a fixed version via a vendor-supplied patch as soon as possible:

Extracted Entities