Deserialization: What the Heck *Actually* Is a Gadget?Chain?

Deserialization: What the Heck *Actually* Is a Gadget?Chain?

So if you’ve been in the security space these past couple of years, there probably is one attack that you heard over and over again: Insecure Deserialization.

It’s not only ubiquitous but also critically severe, often leading to Remote Code Execution and causing widespread panic (remember Log4Shell? Ha, of course, you do!).

If you’re a normalo like me, you understand the idea of insecure deserialization vulnerabilities. You may even have used ysoserial (https://github.com/frohoff/ysoserial) or ysoserial.net (https://github.com/pwntester/ysoserial.net) and gained RCE on a training machine yourself. But there is one thing that you weren’t quite able to wrap your head around yet: Gadget Chains.

So what is a gadget chain?

A gadget chain is a chain of function calls from a source method, generally readObject, to a sink method which will perform dangerous actions like calling the exec method of the Java runtime.(https://www.synacktiv.com/en/publications/finding-gadgets-like-its-2022)

That sort of makes sense but what does this mean in easier words? Let’s ask ChatGPT:

Ha, I think I get it now! So, in essence, gadget chains are how attackers can create malicious objects that, when deserialized, end up executing arbitrary commands.

There is one fantastic article about tracing down a gadget chain in the yii framework: https://blog.redteam-pentesting.de/2021/deserialization-gadget-chain/. Big props to the author for this! However, as the author acknowledges, it is also complex as f*ck and personally took me hours to read through to sort of understand.

So how can we better understand what a gadget chain actually means? Well, by writing our own gadget of course!

Okay, say we have an application that does… books! One of its functionalities is serializing book objects to send them around between the multiple microservices of our book application. Our Book.java may look something like this:

public final class Book implements Serializable {
   public String title;
   
   public Book(String title) {
      this.title = title;
   }
  
   @Override
   public String toString() {
      return "Book [title=" + this.title + "]";
   }
}        

We also have our HomeController.java which is a simple REST controller and may look something like this:

public class HomeController {

  @RequestMapping("/serialize")
  public String serialize() {
    Book myBook = new Book("A cool book!");
    return serializeBook(myBook);
  }

  @PostMapping("/deserialize")
  public String deserialize(@RequestBody String bookBase64) {
    Book myBook = deserializeBook(bookBase64);
    return myBook.toString();
  }
}        

The implementations of serializeBook() and deserializeBook() are as follows:

/**
 * Serializes a Book object and returns it as base64 string
 */
private String serializeBook(Book myBook) {
   ByteArrayOutputStream baos = null;
   
   baos = new ByteArrayOutputStream();
   ObjectOutputStream oos = new ObjectOutputStream(baos);
   oos.writeObject(myBook);
   oos.close();
  
   return Base64.getEncoder().encodeToString(baos.toByteArray());
}

/**
 * Deserializes a base64 string back into a Book object and returns it
 */
 private Book deserializeBook(String base64SerializedBook) {
   Book someBook = null;

   byte[] data = Base64.getDecoder().decode(base64SerializedBook);
   ObjectInputStream ois = new ObjectInputStream(
      new ByteArrayInputStream(data)
   );
 
   someBook = (Book) ois.readObject();
   ois.close();
   return someBook;
}        

Please note that things like exception handling have been omitted for simplicity.

But so far so simple, right? We have a REST service with 2 endpoints:

  • One to serialize a book which returns the base64-encoded, serialized, book object
  • Another one that takes in that base64 string, deserializes the book object, and returns it

And this is obviously dangerous already, right? We know that!

A malicious actor (you gotta love this term, right?) could serialize a malicious object and may be able to execute arbitrary commands when the object is deserialized. Why again? Ah, yeah, because of gadget chains. That’s why we’re here, right?

Gadget chains usually target public libraries?—?to be precise, such public libraries in which very smart security researchers have already found gadget chains. For example, ysoserial has exploits that may work against these common dependencies:

This means that if your app has a Deserialization vulnerability and uses any of the above libraries, an attacker might be able to exploit your app using ysoserial. Well, in theory at least…

It turns out that Java has been doing a good job locking down itself against these gadget chains which means that developers might be in luck if they use a recent version of Java. I played around with this a bit in August 2022 and wasn’t able to leverage most of these known gadget chains against a test app running on an up-to-date Java version?—?but some still worked. As an example, one that still worked (as of August 2022) was FileUpload1:

  • This requires the vulnerable app to use commons-fileupload:1.3.1 and commons-io:2.4
  • To create our malicious serialized payload, we can run: java -jar ysoserial.jar FileUpload1 'write;/tmp;HACKEEED' | base64
  • Now, we send this to our app, and, upon deserialization, a randomly named file will be created in /tmp (e.g. /tmp/upload_1e2897d1_aac7_4210_8911_57cbb6ac37c0_00000000.tmp) with the content 'HACKEEED'

But, we are here because we want to write our own gadget, so let’s get back to this!

Okay, so let’s come back to our very simple book application. Say the app is going really well, customers love it, and we need more functionality. PM says that we need to do something with a book everytime it is deserialized. And what exactly? Ah, we want to run an OS command every time a book is deserialized. That… makes sense. I guess?

So how do we do this? Turns out there are some magic functions that automatically run under certain conditions without them being invoked! Because of how magic this is, they are called “Magic Methods”. One of them is called readObject and if you implement this in Book.java, it will automagically be called whenever a book is deserialized. That’s exactly what we need!

Thus, we adjust our Book.java and it looks something like this:

public final class Book implements Serializable {
   public String title;
   public String cmd;
   
   public Book(String title, String cmd) {
      this.title = title;
      this.cmd = cmd;
   }

   @Override
   public String toString() {
      return "Book [title=" + this.title + ", cmd=" + this.cmd + "]";
   }

   private void readObject(ObjectInputStream in) {
      in.defaultReadObject();

      // ... some more logic and ultimately execute `this.cmd`
      execute(this.cmd);
   }  
}        

Now, say we are the attacker and we want to exploit this. To do this, we need to serialize a malicious object. So we create EvilBook.java:

public class EvilBook {

  public static void main(String[] args) {
    Book book = new Book("someTitle", "curl https://<our_collaborator_URL>");
    String bookSerialized = serializeBook(book);

    FileWriter fileWriter = new FileWriter("naughty_Book.ser");
    PrintWriter printWriter = new PrintWriter(fileWriter);
    printWriter.print(bookSerialized);
    printWriter.close();
  }

  /**
   * Serializes a Book object and returns it as base64 string
   */
  public static String serializeBook(Object myBook) {
    ByteArrayOutputStream baos = null;
    
    baos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(baos);
    oos.writeObject(myBook);
    oos.close();

    return Base64.getEncoder().encodeToString(baos.toByteArray());
  }
}        

So what is happening here? Our serializeBook() simply takes in a book object again, serializes it, and encodes it to a base64 string. Just like we have done before.

And our main()? This creates a book object that uses this new cmd property which we added to Book.java. If this command would actually execute, it would fire curl https://<our_collaborator_URL>, which would send a request to a server under our control and would show us that we can indeed execute commands.

What else happens in main? Not much actually, we simply create a book object with this cmd?, serialize it to a base64 string, and store this string in a file that we call naughty_Book.ser. We could also call it florian.txt but let’s stick with naughty_Book.ser for now.

So we compile and run our EvilBook.java, it outputs naughty_Book.ser, and then? We simply send the content of naughty_Book.ser to the /deserialize endpoint of our HomeController.java. This would deserialize the naughty_Book, and automatically call our custom readObject() method (because it’s a magic method, ae!) within Book.java?—?which looked like this:

private void readObject(ObjectInputStream in) {
   in.defaultReadObject();

   // ... some more logic and ultimately execute `this.cmd`
   execute(this.cmd);
}        

And execute(this.cmd) would execute our curl command. And we have Remote Code Execution!

Closing Thoughts

That’s it! A super simple example of pretty much everything that Insecure Deserialization entails. We discussed object serialization, deserialization, and magic methods, and implemented our own gadget. That’s, in a nutshell, how deserialization vulnerabilities look under the hood?—?only it’s usually more complicated than this.

If you wanna dive a bit deeper into the topic, or play around with my example, you can do this! You can explore this example further?—?and more?—?at my GitHub repository: https://github.com/dub-flow/java-gadget-chain.

I genuinely hope this little story was useful to you. If you have any thoughts on the topic or anything else you’d like to share, feel free to reach out.

Sanadhya K.

Mobile Application Security | API Security | OSINT

1 年

Insecure deserialization read write read ??

回复
Albert C.

IT Manager | Cybersecurity | PMP-PMI | Harvard | eWPTX | CWL MCRTA | CompTIA Sec+ | SCRUM Master & Product Owner | Google & Microsoft Cloud | Podcast Coffee&&Pizza | Creator of HackingWebinars & Cybermentor Institute

1 年

I'm just with this, then it was a perfect fit ????

Jayadithya G

CSE Undergrad | Aspiring Cyber Security & Blockchain Professional | CTF Player | Exploring Web3.0 | Hackathon Enthusiast | Learning AI/ML | Seeking Internship Opportunities

1 年

Interesting!

要查看或添加评论,请登录

Florian Walter的更多文章

  • Hacking Moodle Apps Via External Functions

    Hacking Moodle Apps Via External Functions

    So say you’re trying to hack an app that uses Moodle. You start by googling something like “hacking moodle” or “moodle…

    3 条评论
  • Found a Vulnerability? 3 Easy Steps to Submitting a CVE!

    Found a Vulnerability? 3 Easy Steps to Submitting a CVE!

    In my recent post, I talked about the methodology that I used to find most of my 25 CVEs (you can find this article…

    4 条评论
  • Hacking Large Language Models — A Case Study

    Hacking Large Language Models — A Case Study

    In this article, I will show how I was able to “jailbreak” a language model and make it drop its “no I won’t do this”…

    2 条评论
  • How Secure is Java’s SecureProcessing?

    How Secure is Java’s SecureProcessing?

    If you’ve ever worked with secure XML parsing in Java (to prevent XXE Injections), you probably have come across an XML…

    3 条评论
  • Predicting a “Random” Number

    Predicting a “Random” Number

    Have you ever looked at a code snippet that creates for example a password reset token or something, uses a…

    9 条评论
  • Subdomain Takeover: What is It? How to Exploit? How to Find Them?

    Subdomain Takeover: What is It? How to Exploit? How to Find Them?

    In this article, we shed light on Subdomain Takeovers and discuss 3 things: What is a Subdomain Takeover? How to…

  • AI vs. Human: Who is the better Vulnerability Researcher? ????

    AI vs. Human: Who is the better Vulnerability Researcher? ????

    In the evolving landscape of cybersecurity, the rise of AI tools like ChatGPT has opened new horizons in code analysis…

    1 条评论
  • How I Became an Ethical Hacker

    How I Became an Ethical Hacker

    People often ask me (they actually do! ??) how they can break into the field of cybersecurity (and, particularly…

    11 条评论
  • Bruteforcing Files and Directories is Easy... Right?

    Bruteforcing Files and Directories is Easy... Right?

    Well, yeah, it is. You just provide a URL and a wordlist, feed it into a tool like gobuster or ffuf, and wait for the…

    14 条评论

社区洞察

其他会员也浏览了