top of page

Exploiting Insecure Deserialization - A Real-World Case Study

  • Writer: idan ba
    idan ba
  • Sep 2
  • 4 min read

Updated: 12 hours ago


Setting the Stage


At Cybenari, we frequently encounter interesting vulnerabilities during penetration tests. Recently, while testing a client’s production application, we uncovered an insecure deserialization issue that could have opened the door to serious exploitation.


This post walks through how we found it, the technical details, and why deserialization bugs remain one of the most dangerous classes of vulnerabilities.



A Suspicious Base64 String


During routine testing, I noticed that my browser was sending a base64-encoded string to the application. At first glance, I assumed it was just a JSON Web Token (JWT). But something didn’t quite fit - the structure just wasn’t right.


ree

Decoding the base64 string revealed something even more curious, it contained values that looked like Java class packages. This immediately raised a red flag. Could this be a serialized Java object being passed around?


ree

Curiosity led me deeper, and after further investigation, I confirmed that the application was indeed serializing and deserializing Java objects directly. That’s when things got really interesting....



A Quick Primer - Serialization & Its Risks


Serialization is the process of converting an object into a format (like a text, bytes or base64) that can be stored or transmitted. Deserialization is the reverse process - turning that representation back into a live object.


The danger arises when applications blindly trust serialized input. If an attacker can tamper with that serialized data, they might be able to craft malicious objects that trigger unexpected behavior - including arbitrary code execution (RCE).



Crafting the Exploit a story of trial and error


With confirmation that the app was deserializing Java objects, I began my exploitation attempts. Because I had access to the source code, my first thought was to build a custom exploit by serializing my own Java object which will have similar fields and methods like the Java object the server is expecting to find. Unfortunately, this approach didn’t get me anywhere...


Next, I turned to ysoserial, a well-known open-source tool for generating deserialization payloads. YSoSerial provides dozens of “gadget chains” — reusable sequences of Java classes that can be abused to perform unintended actions during deserialization. In the past I didn't have much luck with ysoserial, so I was a bit skeptic about this approach.



Buy What’s a Gadget Chain anyway?


A gadget chain is a series of existing classes and methods within a program or library that can be “chained” together to achieve malicious effects.


In deserialization attacks, attackers don’t need to upload new code - they simply exploit what’s already present on the classpath. The default deserialization process of Java initiates the start of this process, but the exploit causes it go down a "chain" that ends up running code that can be potentially harmful.


Think of it like stringing together Lego blocks that weren’t meant to fit, but when combined in a certain way, they create a dangerous contraption.



Running into Roadblocks


Armed with ysoserial, I tried every available gadget chain, but success didn’t come easily.

  • Some payloads were too large and were blocked by the client’s CDN.

  • Others triggered the WAF and were stopped before reaching the app.

  • Some required libraries the application didn’t use.

  • A few were even blocked by Apache, as I noticed in the logs.


After days of trial and error, the breakthrough came with the URLDNS gadget chain!



Proof of exploitation using DNS Callbacks

Using the URLDNS gadget, I was able to get the application to make outbound DNS queries to my Interactsh server!

The payload looked like this:

java -jar ysoserial-all.jar URLDNS "https://server.com" | base64
ree

I sent the base64-encoded payload to the vulnerable endpoint and successfully received a DNS request from the target. This was the proof I was waiting for!


DNS Queries hitting my interacsh server from the vulnerable serve
DNS Queries hitting my interacsh server from the vulnerable serve

While I wasn’t able to escalate this to full remote code execution (RCE), the fact that external communication was possible strongly suggested the risk was real. With more targeted gadget chain research, RCE might still be achievable.



Fixing the Issue


Fortunately, the fix was straightforward. Instead of naively deserializing untrusted input, the development team updated the code, following my guidance, to:

  1. Decode the base64 string.

  2. Sanitize and validate the data.

  3. Only then proceed with deserialization.


By applying validation before deserialization, they effectively closed the vulnerability.



Severity Matters

This issue was particularly severe because the vulnerable endpoint was part of the email confirmation process, which occurred before the user is ever authenticated. That meant attackers wouldn’t need valid credentials to exploit it making it a prime candidate for external attacks.



Quick Detection Tip

If you’re a pentester reviewing HTTP traffic and see base64-encoded values starting with the prefix rO0 or rO0AB you are probably looking at a serialized Java object. That’s your cue to dig deeper.

ree

Takeaway

Insecure deserialization remains a serious attack vector, even if it doesn’t always lead directly to RCE. The moral of the story - never deserialize untrusted input without validation. What seems like a harmless base64 string could turn into an attacker’s entry point.



Aftermath

After resolving the vulnerability, we didn’t stop there. We took the vulnerable code pattern as a reference point and performed a broader search across the client’s entire GitHub organization. Our goal was to identify whether similar serialization practices existed in other services or repositories.


This hunt uncovered some interesting insights about how serialization had crept into different parts of the codebase in subtle ways but that’s a story for another time...



bottom of page