Deserialization Vulnerabilities

What is Serialization and Deserialization?

It’s a way for an object to be converted in to a stream of bytes or similar, allow it to be stored or processed by other services such as databases, memory and files or sent across a network to a server. The byte stream can then be deserialized back in to it’s original object.

How can this be a problem?

Let’s take a look at NodeJS as it’s easy to see the process due to objects being serialized to a string. The package used to serialize an object is called node-serialize.

If we look at the code behind node-serialize we can see that in the unserialize method uses a javascript function called eval (Line 76).

What does eval do?

Take a look at this example.

Here we are setting a variable to a stringified function. We then use eval to turn that string in to functioning code. So it takes the string and turns it in to an actual function which just returns the word ‘test’. However if we were to use an Immediately-Invoked Function Expression by adding an addition ‘()’ with eval it will actually execute that function as you can see in the last example.

How can this be used for exploitation?

To demonstrate how this can be exploited, I’ve created a small application. It’s a simple web page that does the following:

  • Takes the users name and location on first visit
  • Stores the values in a JSON Object
  • Serializes the Object
  • Base64 Encodes the serialized object
  • Stores the base64 string in a cookie.

On return visits, the web app checks for the cookie and uses the value to reverse the process and display a greeting to the user.


(Source code available on GitHub: https://github.com/Largoat/serialization-demo-webapp)

So let’s see the application is use.

Now we’ll take that cookie value, URL decode it and then base64 decode and we’ll be given a JSON object. If we change the values and re-encode the JSON and save the value in the cookie we can see that upon refreshing our web application those changes have taken effect.

So let’s think back to how eval works and replace the JSON values with a function.

The output of this script would be;

{"name":"Bill","from":"_$$ND_FUNC$$_function () {\n return 'Test';\n }"}

We can then IIFE the function inside the serialized string, base64 encode and copy the value to our cookie. The result should be that the location will show as ‘Test’.

This means that we actually have the ability to run javascript on the server, rather than just on our client. This is very dangerous! NodeJS comes bundled with lots of different packages that allow us to do various different things.

Let’s take a look at this example:

Here we are doing the following:

Created a function as the value of ‘name’ in the JSON Object
including the ‘net’ package from NodeJS which allows us to create a network connection
including the ‘child_process’ package from NodeJS which allows us to spawn new processes.
Spawning a new shell using ‘child_process’
Connecting to another machine on port 8080 (the IP was set to localhost for this demo as both attacker and victim were on the same machine. This could actually be any IP address)
Binding the shell process to the network connection
Returning a string to keep the application happy.
We then serialize this, IIFE as before and then on to encoding and dropping in to the cookie. Next we set Netcat to listen for incoming connection on port 8080.

As you can see from the clip, we now have a reverse shell on to the server from an external source, all because client data has been trusted and run through one function… eval.

Not just NodeJS

It’s not just NodeJS that suffers from this issue. Any language that uses serialization and deserialization is prone to these types of vulnerabilities. In fact one technology that we use here is prone to such a thing…

WebLogic has the same issues. Take a look at King, Owen ‘s demo of the vulnerability: Deserialization in Weblogic

In an attempt to fix the issue with WebLogic, Oracle tried to Blacklist the packages that were allowing these exploits to work (unintentionally), but as soon as a patch was released, another route in to the same exploit was found.

This is the problem with trying to Blacklist packages in an attempt to fix Deserialization vulnerabilities. You can never blacklist them all and even if you get close, you’re adding a severe amount of bloat to your code. You may as well have done it properly and not use serialization at all right?

So what are Oracle doing to fix this huge security flaw in Java?

They’re not. They’re completely dropping serialization in java because it just cannot be fixed.

As I mentioned previously, it’s not just NodeJS or Java that have these issues but any language that serializes and deserializes such as .Net and PHP.

Prevention

The only way to prevent these vulnerabilities is to just not use Serialization at all. Make sure the applications or packages that you’re using do not have the vulnerabilities and make sure your servers or applications are configured correctly to prevent these issues.