Code Injection During Deserialization

ID

csharp.code_injection_deserialization

Severity

critical

Resource

Injection

Language

CSharp

Tags

CWE:502, NIST.SP.800-53, OWASP:2021:A8, PCI-DSS:6.5.1

Description

Improper deserialization of untrusted data, possibly allowing code injection attacks.

Deserialization vulnerabilities arise when an application deserializes user-controlled data without proper validation, potentially allowing attackers to instantiate unexpected objects or execute crafted functions leading to arbitrary code execution or system exploits.

Rationale

After detecting the vulnerable site, attackers typically craft a payload that is serialized and sent to the application. If the application deserializes this payload without validation, attackers can modify the expected data structure to escalate privileges or perform unwanted actions.

In the worst case, the attackers inject an object of an unexpected type, triggering chosen code execution. This could be used to exfiltrate internal server’s data, install malware e.g. to install and persist crypto-miners, or run a reverse shell.

The C# serialization mechanism provides a way to convert objects into a byte stream, which can later be converted back into a copy of the object. When dealing with untrusted input for deserialization, attackers can craft malicious object streams that, upon deserialization, invoke code paths within the application or libraries loaded into the application environment, typically leading to code injection exploits.

Here is an example of insecure C# deserialization:

using System.Web;
using Newtonsoft.Json;

// Example using the popular Json.Net
public class Deserializer {
  public Product deserializeProduct(HttpContext context) {
    string json = context.Request.Item["json"];
    // VULNERABLE, too permissive type control
    return JsonConvert.DeserializeObject<Product>(json, new JsonSerializerSettings() {
      TypeNameHandling = TypeNameHandling.All
    });
  }
}

This example demonstrates unsafe deserialization. If json is maliciously crafted, it can potentially execute harmful code or instigate other vulnerabilities in the application.

Remediation

If possible, do not deserialize content to objects when the source is not fully trusted.

Mitigating deserialization vulnerabilities involves several key practices:

  1. Avoid Deserialization of Untrusted Input: The most secure approach is to avoid deserializing any untrusted data outright. If deserialization is necessary, consider other safe data formats such as JSON or XML with strict schema validation.

  2. Use Secure Libraries: Employ libraries or frameworks that provide secure deserialization mechanisms.

  3. Validation and Whitelisting: Implement strict validation. Use a whitelist approach where only the expected, permitted, and safe classes are allowed to be deserialized.

The vulnerability shown before can be fixed by using the default, much more restrictive TypeNameHandling.None setting:

using System.Web;
using Newtonsoft.Json;

// Example using the popular Json.Net
public class Deserializer {
  public Product deserializeProduct(HttpContext context) {
    string json = context.Request.Item["json"];
    // FIXED, the default TypeNameHandling.None is much more strict
    return JsonConvert.DeserializeObject<Product>(json, new JsonSerializerSettings();
  }
}

Which libraries should I use for deserialization, and how?

In short, some libraries (FastJSON, Sweet.Jayson, FSPickler) should NEVER be used with untrusted sources. Others might be configured incorrectly to open deserialization flaws, typically when a too-much permissive type resolver is used: Json.Net, JavaScriptSerializer, DataContractJsonSerializer…​

If the attacker cannot control the content to be deserialized, typically there is no problem per-se with these libraries. And even when the attacker can control such content, the types to be deserialized may be fixed by the application, or limited to a white-list of allowed types, and that makes deserialization safe, at least for most libraries. For example, XmlSerializer or DateContractSerializer are safe when the type is fixed to a safe type. JSON.Net is also typically safe when TypeNameHandling is set to None (but vulnerable otherwise, be careful).

Please note that most libraries using binary formats, including .Net’s BinaryFormatter, are fairly difficult to configure for safe type control against attack payloads in user-controlled content.

Configuration

The detector has the following configurable parameters:

  • sources, that indicates the source kinds to check.

  • neutralizations, that indicates the neutralization kinds to check.

Unless you need to change the default behavior, you typically do not need to configure this detector.

References

There are interesting .NET-specific references to the vulnerability, such as: