Serialization is the process of transforming objects such as instances of specific classes into a serial form. An in-memory data object can be transformed into a binary stream while maintaining the current state of the object. Deserialization is the reverse process; an incoming stream of data is read and transformed into one or more data structures.
Serialization Attacks 101
A serialization attack happens when an attacker passes a compromised serialized object (e.g., a modified JSON payload) to an application or API endpoint. The attacker hopes that the target will deserialize the hostile data directly into an in-memory structure.
A successful serialization attack can have a variety of consequences, including RCE (Remote Code Execution). This is a worst-case scenario; an attacker gains the ability to execute code in your organization’s systems, leaving them wide open to exploitation such as data compromise, or even ransomware.
Obviously a serialization vulnerability can eventually have severe business impacts, with devastating implications to an organization’s credibility, data confidentiality, and operational activities. The potential consequences have led the OWASP (Open Web Application Security Project) to include insecure deserialization in its list of Top 10 Web Application Security Risks.
Despite this, serialization tends to be a lesser-known threat vector than, say, DDoS or ATO (Account Takeover) attacks. It’s true that serialization attacks are less common than most other malicious web activities; each attack requires a high level of expertise from the threat actor, and must be customized to the system being targeted. However, they also tend to be more challenging to defend against. For example, as OWASP notes, some deserialization vulnerabilities can be detected with automated tools, but human intervention and skill is still necessary to find others.
When Are We Vulnerable?
An application could be vulnerable to serialization attacks when it exposes an interface that expects serialized data to be loaded. For example, if information related to a user’s web session is saved in a client cache using cookies (such as username, user ID, and role), then an attacker could tamper with that cookie data (e.g., change the role from “user” to “admin” and gain a higher level of access to the system). Of course, this basic example is fairly trivial for a developer to prevent, but it illustrates the concept.
In a world that is more and more connected and API-driven, the ability to make requests using custom serialized payloads is increasing. In addition to modifying payload content and violating the structure of data and objects, attackers can also take advantage of any classes in the application that can change behavior during or after deserialization.
It’s worth reflecting on where application developers are using serialization regularly. The number of these points can be quite extensive, for example: HTTP form parameters and cookies, authentication tokens in API, RPC/IPC (remote procedure call and inter-process communication), databases, cache systems, and operations on files.
A common misconception is that vulnerabilities related to serialization and deserialization mainly affect Java; this is due to dangerous flaws discovered in 2015 in the Apache Commons Collections. Nevertheless, deserialization issues affect many popular programming languages such as PHP, Python, .Net, and C#, among others.
A Prominent Example
The Java deserialization flaw mentioned above is a good example of how severe these vulnerabilities can be. This one affected a common library, and exposed servers to being exploited via popular software such as WebLogic, WebSphere, JBoss, and Jenkins. This vulnerability allowed anyone using tools such as the Burp Suite with crafted plugins like the Java Serial Killer and GadgetProbe to view a malformed serialized body of an HTTP request/response. Further, they could use tools like ysoserial to modify it with the intent of performing RCE on the application server that the Java-based application was communicating with. This vulnerability wasn’t fully patched until 11 months after it was first publicly revealed.
Another example is based on Adobe’s BlazeDS AMF deserialization vulnerability, CVE-2011-2092. This vulnerability impacts the Adobe LiveCycle Data Services in earlier versions where it was not able to limit class creation during data deserialization. In this scenario, a BlazeDS application will deserialize special classes and properties as defined by the attacker. More details on this example can be found here.
Best Practices to Defend Against Serialization Attacks
How can we harden applications and systems against this type of vulnerability?
A first, albeit basic, best practice is to design applications that limit the approval of serialized objects from foreign sources. An alternative could be to use mechanisms that only allow serialization of primitive data types. Also, make sure to limit the allowed data types during object creation.
However, it’s worthwhile to go beyond simply limiting access, and have a business logic that can check the integrity of serialized objects to make sure that no hostile manipulated objects have been created. For example, Reblaze includes mechanisms in its cloud WAF to create and enforce content filtering (allowing and/or excluding requests based on the content of the HTTP requests).
In some situations, communications can be cryptographically signed. For example, Reblaze has a client-side SDK for mobile applications. Developers compile their apps with the SDK included. In use, it authenticates every client and ensures that communication with the server cannot be tampered with.
Another interesting API security approach is to separate the environment in which a specific application operates. You should use a sandbox whenever possible with separate privilege rules, giving only the minimum permissions necessary. This will minimize the risk of one role being able to take control of the system.
Always be careful if an application reports deserialization exceptions. Make sure to log such incidents and analyze the data continuously to identify potential attack attempts. Each deserialization operation should be monitored, and any detected anomalous behavior during the deserializing process should be immediately flagged and raise suspicion.
In the era of ubiquitous containerization and software-defined networks, it is also advisable (and fairly easy) to limit the network connectivity of applications that deserialize data.
Lastly, it’s highly recommended to carefully go through the OWASP Deserialization Cheat Sheet, which includes (among other things) specific best practices for a number of languages.
It’s vital to understand serialization/deserialization and the potential security implications associated with these mechanisms in the context of your own applications and APIs. Although these attacks aren’t common, they can be devastating when they occur. Threat modeling should be used to identify the most vulnerable points in your systems, and the best practices described in this article can help mitigate attack vectors.
With a constantly evolving threat landscape, it’s important to remember that preventing serialization attacks requires unflagging vigilance. Maintaining web application and API security is a continuous process.