Skip to content

Latest research: Read the advisory

All research
CVE AnalysisWeb SecurityDeserializationCVE-2023-34362 9.8

MOVEit Transfer CVE-2023-34362 & CVE-2023-35036: from SQL injection to .NET deserialization RCE

Dau Hoang Tai· Co-Founder8 min read

The MOVEit Transfer bug that drove one of 2023's largest breach waves, taken apart end to end: an unauthenticated stacked SQL injection, privilege escalation by inserting an admin, an IP-whitelist bypass, and finally unsafe .NET deserialization for code execution. Plus the second injection, CVE-2023-35036.

MOVEit Transfer is a managed file-transfer server: SFTP, FTPS, HTTPS and AS2, with access controls and encryption on top. In mid-2023 it became the epicenter of one of the year's largest breach waves. CVE-2023-34362 (CVSS 9.8) is the reason. This is a full walkthrough of the chain, followed by the second SQL injection, CVE-2023-35036 (CVSS 9.1), that shipped in the same family.

Standing up a MOVEit Transfer trial to analyse it.
The analysis starts where every good one does: a real instance in a lab.

The shape of the chain

CVE-2023-34362 is not a single bug, it is a chain of four steps, each covering the gap left by the last:

  1. 01Unauthenticated SQL injection in the file-transfer web interface.
  2. 02Privilege escalation by inserting an attacker-controlled admin account.
  3. 03An IP-whitelist bypass to reach an internal-only endpoint.
  4. 04Unsafe .NET deserialization to turn database control into code execution.
Setting up the MOVEit Transfer 2023.0 build used for the analysis.
MOVEit Transfer 2023.0 — the version analysed in the original write-up.

Step 1: the SQL injection

The injection lives in the UserGetUsersWithEmailAddress method inside UserEngine.cs. Reaching it does not require a session in the normal sense: the exploit manipulates MOVEit's session variables through request headers and drives the injectable code path via the guestaccess.aspx endpoint. Because the injection is stacked (multiple statements per query), the attacker is not limited to reading data — they can execute arbitrary INSERT/UPDATE statements against the backing database.

Step 2: escalate by inserting an admin

With write access to the database, the attacker inserts a new administrator account directly into the users table. MOVEit trusts its own tables for identity, so a row is an account. From there they hold admin privileges without ever knowing a password.

Step 3: bypass the IP whitelist

The deserialization sink lives behind machine2.aspx, an endpoint intended to be reachable only from trusted, whitelisted hosts. Two problems combine to defeat that control:

  • The IP allow-list itself is stored in the hostpermits table, which the stacked injection can write to. Insert the attacker's address and you are "trusted".
  • Request processing by the ISAPI extension (moveitsapi.dll) can be bypassed by embedding the header values it expects inside Cookie fields, enabling an SSRF-style reach into machine2.aspx.

Either way, the internal-only endpoint is now in reach.

Step 4: unsafe .NET deserialization

The endpoint's DeserializeFileUploadStream method deserializes untrusted .NET objects read from the State column of an upload record. The exploit uses a two-stage upload: an initial partial upload stores the serialized payload in that column, and completing the upload triggers deserialization of it. A crafted gadget in the payload turns that deserialize into remote code execution.

Chain the four steps and the result is unauthenticated RCE on the MOVEit server — which, given what MOVEit is used for, means direct access to exactly the sensitive files organizations deployed it to protect.

CVE-2023-35036: the second injection

Progress's follow-up review surfaced a second SQL injection, patched as CVE-2023-35036. This one is in the FolderIDToPath method, which concatenates user-controlled input straight into a query. The CleanForSQL sanitizer only strips ', " and ;, so it misses backslash escape sequences entirely. The injectable input arrives through the X-siLock-FolderID and X-siLock-RelativePath headers.

There is a second vector too: SILCertToUser.cs interpolates the Common Name (CN) field of a client certificate directly into a query — though that path additionally requires already-trusted-IP status, which step 3 above happens to provide.

Mitigation

  • Patch MOVEit Transfer to a fixed release for both CVE-2023-34362 and CVE-2023-35036, and follow Progress's advisories.
  • Assume compromise if you ran a vulnerable version while it was exposed: hunt for unexpected admin accounts, rows added to hostpermits, and web shells or unfamiliar files dropped by the deserialization step.
  • Restrict network exposure of the web interface; a managed file-transfer server rarely needs to be open to the whole internet.
  • The durable fixes are architectural: parameterized queries everywhere, no deserialization of untrusted State, and identity that does not live in a table a single injection can write to.

Dau Hoang Tai

Co-Founder, Starfish Security

LinkedIn