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.

Sticky Keys

I’ve recently taken part in a Cyber War Games event where I learnt quite a lot about a variety of things. One of the more interesting things was the Sticky Keys exploit on Windows.

For those that don’t know, Sticky Keys is an accessibility feature in Windows that allows the user to press and release modifier keys (Ctrl, Shift, Alt etc) rather than have to hold them. It can be activated at any time by pressing Shift 5 times.

The vulnerability isn’t actually with the Sticky Keys executable itself, but more the fact that Windows will just launch the executable when Shift is press 5 times, meaning that it can be replaced with another executable such as cmd.exe. It’s also run as the SYSTEM user from the logon page which means you’d get a command prompt at the SYSTEM user, allowing you to perform a variety of other commands.

Exploiting

For this vulnerability to work, the attacker first needs physical access the to computer. In this demo, I’ll use a Kali Linux Live USB stick on a Windows 10 Laptop.

Insert the Kali Live USB and boot to it. Next we need to mount the Windows partition using ntfs-3g (Install it if you don’t have it already, but it comes bundled with Kali). You can use fdisk -l to list all the connected disk drives and their partition.

[email protected]:~# mkdir -p /mnt/win10
[email protected]:~# ntfs-3g /dev/sda2 /mnt/win10
[email protected]:~# cd /mnt/win10

Now that we have the Windows partition mounted we then need to make a backup of the Sticky Keys executable and replace the original with cmd.exe.

[email protected]:/mnt/win10# cp Windows/System32/sethc.exe Windows/System32/sethc_1.exe
[email protected]:/mnt/win10# cp Windows/System32/cmd.exe Windows/System32/sethc.exe

Now shutdown, remove the Kali Live USB and boot up again in to Windows.
On the Password Entry screen, press shift 5 times and you should be given a command prompt. From here you can change existing users, add new users, add people to groups such as Administrator and lots more.

Prevention

To prevent this particular vulnerability you can do several things but I’d advise all of them if you want to be really secure…

Disable Sticky Keys

You can disable this from the Sticky Keys app itself or in your control panel. It should prevent Windows from launching the app.

Disable booting from USB Devices

This won’t work if someone physically removes your drive and plugs it in elsewhere, but at least it offers protection from someone walking up and performing this exploit.

Password Protect the BIOS

Combined with the above, it means that no one can make changes to your BIOS settings without knowning the password.

Encrypt your Windows drive

You can use the built in BitLocker with Windows to protect the data on your drive. This means that even if someone does get hold of the drive, they’ll need to break the encryption first before they can perform this exploit.