Manual Testing for Insecure Deserialization
Insecure deserialization remains one of the most critical and often overlooked vulnerabilities in web applications. In this article—part of the “Learn Pentesting” series—we will perform a technical deep-dive into manually testing for insecure deserialization. We’ll cover the underlying concepts, demonstrate several manual testing techniques, and walk through practical code examples. This post is intended for penetration testers and security professionals who seek a robust technical reference.
1. Understanding Serialization and Deserialization
Serialization is the process of converting an object into a format that can be stored or transmitted (such as JSON, XML, or binary), and deserialization is the reverse process—converting serialized data back into an object. Insecure deserialization occurs when an application unserializes untrusted data without proper validation, enabling an attacker to inject malicious objects. This can lead to severe outcomes including remote code execution (RCE) and privilege escalation.
For example, consider an object serialized by PHP or Python. If an application blindly unserializes this data, an attacker might manipulate the serialized stream to instantiate arbitrary objects or execute unintended code.
2. Identifying Potential Insecure Deserialization Points
When assessing a web application, look for endpoints or functionalities that:
- Accept serialized data (via POST bodies, cookies, or URL parameters).
- Use functions or libraries such as
unserialize()
in PHP,pickle.loads()
in Python, or Java serialization APIs. - Lack proper integrity checks, such as digital signatures or strict schema validation.
A systematic approach involves:
- Reviewing source code (if available) to identify deserialization routines.
- Analyzing API documentation and request/response patterns for hints of serialized objects.
- Observing error messages which may leak class names or other serialization-specific data.
3. Manual Testing Techniques
Intercepting and Modifying Serialized Data
Using tools like Burp Suite or OWASP ZAP, intercept the HTTP request containing the serialized payload. Examine its structure—often encoded in base64 or hex. Modify parts of the payload to:
- Change object properties.
- Inject unexpected object types.
- Introduce custom payloads that might trigger methods like
__wakeup()
or__destruct()
.
For instance, if you see a serialized PHP object, you might alter its internal state to observe how the server reacts. Note any error messages that reveal underlying class structures.
Error Analysis and Fuzzing
Error messages can be invaluable. If the application responds with errors that include stack traces or class names, it provides insight into what objects are being deserialized. This information can guide your crafting of malicious payloads.
A fuzzing approach involves automating the submission of malformed or altered serialized data. Monitor server responses for deviations, which might indicate insecure handling.
4. Real-World Code Examples
PHP Unserialization Example
Consider a PHP application that uses unserialize()
on user-provided data:
<?php
class User {
public $name;
public function __wakeup() {
// Potentially unsafe behavior on deserialization
echo "Welcome, " . $this->name;
}
}
if (isset($_GET['data'])) {
// Assume the serialized object is base64-encoded
$data = base64_decode($_GET['data']);
$obj = unserialize($data);
// Further processing...
}
?>
Testing Approach:
- Intercept a request containing the
data
parameter. - Decode the payload from base64 to examine the serialized string.
- Modify object properties (e.g., change the
name
value) and re-encode the payload. - Submit the modified payload and observe if the behavior or errors change.
- Look for unintended execution paths within
__wakeup()
or other magic methods.
Python Pickle Deserialization Example
Python’s pickle
module can also be a target if deserialization occurs without validation. Consider the following vulnerable example:
import pickle
import base64
class Exploit:
def __reduce__(self):
import os
# This command will execute when unpickled
return (os.system, ('id',))
def deserialize_data(encoded_data):
# Assume the data is base64-encoded
data = base64.b64decode(encoded_data)
return pickle.loads(data)
if __name__ == '__main__':
# Generate a malicious payload
payload = pickle.dumps(Exploit())
encoded_payload = base64.b64encode(payload)
print("Malicious payload (base64):", encoded_payload.decode())
Testing Approach:
- Generate a malicious payload using the above script.
- Submit the payload to the vulnerable endpoint.
- Analyze the server’s response to confirm whether the payload triggers code execution.
Note: The use of Python’s
pickle
for untrusted data is strongly discouraged. This example is for educational purposes only; never deploy untrusted serialized data processing in production environments.
Java Gadget Chains and ysoserial
In Java environments, insecure deserialization can be exploited through gadget chains—pre-compiled chains of classes that, when deserialized, trigger RCE. A common tool used in testing is ysoserial. While manually crafting these payloads is complex, ysoserial automates the process:
# Generate a payload using the CommonsCollections gadget chain:
java -jar ysoserial.jar CommonsCollections5 'id' > payload.bin
Testing Approach:
- Identify endpoints that accept serialized Java objects.
- Generate a payload using ysoserial.
- Submit the payload to see if you achieve code execution.
While we do not include a full Java code example here, penetration testers should be familiar with ysoserial and its documentation to further explore Java deserialization vulnerabilities.
5. Workflow and Tools for Manual Testing
A streamlined manual testing workflow for insecure deserialization may include:
- Initial Discovery: Identify endpoints that accept serialized data.
- Interception: Use a proxy tool (e.g., Burp Suite) to capture and analyze traffic.
- Decoding: Convert payloads (from base64, hex, etc.) to human-readable forms.
- Modification: Alter the payloads to change object properties, replace object types, or inject malicious payloads.
- Submission and Analysis: Re-send the modified payloads and observe responses for error messages or unexpected behavior.
- Automation/Fuzzing: Where applicable, automate the process with custom scripts to test various payload permutations.
Key tools include:
- Burp Suite / OWASP ZAP: For intercepting and modifying HTTP requests.
- Custom Scripts (Python, Ruby, etc.): To automate payload generation and testing.
- ysoserial: For generating serialized payloads in Java environments.
6. Mitigation Strategies and Best Practices
To protect applications against insecure deserialization:
- Avoid Deserializing Untrusted Data: Where possible, do not allow deserialization of data from untrusted sources.
- Implement Integrity Checks: Use digital signatures or HMACs to ensure serialized data has not been tampered with.
- Adopt Safer Serialization Formats: Use formats such as JSON or XML that do not inherently support complex object graphs and executable code.
- Whitelisting Allowed Classes: If deserialization is necessary, restrict the set of classes that can be deserialized.
- Regular Code Reviews and Testing: Integrate deserialization security checks into your development lifecycle and penetration testing routines.
7. Conclusion
Insecure deserialization is a potent vulnerability that can lead to severe security breaches if left unchecked. Through careful manual testing—intercepting requests, modifying payloads, and analyzing server behavior—penetration testers can uncover these vulnerabilities and help secure applications before they are exploited by malicious actors.
This deep-dive has covered:
- The basics of serialization and deserialization.
- Step-by-step techniques to identify and test for insecure deserialization.
- Practical code examples in PHP, Python, and insights into Java testing with ysoserial.
- Best practices for mitigating the risk of insecure deserialization.
By following the methods and techniques discussed in this post, you’ll be better equipped to evaluate and secure applications against these vulnerabilities. Continue exploring our “Learn Pentesting” series for more technical insights and advanced penetration testing strategies.
Happy Testing!