### SCS0028 - Insecure Deserialization
Untrusted data passed for deserialization.
#### Risk
Arbitrary code execution, full application compromise or denial of service. An attacker may pass specially crafted serialized .NET object of specific class that will execute malicious code during the construction of the object.
#### Vulnerable Code
```cs
private void ConvertData(string json)
{
    var mySerializer = new JavaScriptSerializer(new SimpleTypeResolver());
    Object mything = mySerializer.Deserialize(json, typeof(SomeDataClass)/* the type doesn't matter */);
}
```
#### Solution
There is no simple fix. Do not deserialize untrusted data: user input, cookies or data that crosses trust boundaries.

In case it is unavoidable:  
1) If serialization is done on the server side, then crosses trust boundary, but is not modified and is returned back (like cookie for example) - use signed cryptography (HMAC for instance) to ensure it wasn't tampered.  
2) Do not get the type to deserialize into from untrusted source: the serialized stream itself or other untrusted parameter. `BinaryFormatter` for example reads type information from serialized stream itself and can't be used with untrusted streams:
```cs
// DO NOT DO THIS!
var thing = (MyType)new BinaryFormatter().Deserialize(untrustedStream);
```
JavaScriptSerializer for instance without a JavaScriptTypeResolver is safe because it doesn’t resolve types at all:
```cs
private void ConvertData(string json)
{
    var mySerializer = new JavaScriptSerializer(/* no resolver here */);
    Object mything = mySerializer.Deserialize(json, typeof(SomeDataClass));
}
```
Pass the expected type (may be hardcoded) to the deserialization library. Some libraries like Json.Net, DataContractJsonSerializer and FSPickler validate expected object graph before deserialization.
However the check is not bulletproof if the expected type contains field or property of `System.Object` type somewhere nested in hierarchy.
```cs
// Json.net will inspect if the serialized data is the Expected type
var data = JsonConvert.DeserializeObject<Expected>(json, new
JsonSerializerSettings
{
    // Type information is not used, only simple types like int, string, double, etc. will be resolved
    TypeNameHandling = TypeNameHandling.None
});
```
```cs
// DO NOT DO THIS! The cast to MyType happens too late, when malicious code was already executed
var thing = (MyType)new BinaryFormatter().Deserialize(untrustedStream);
```  
3) If the library supports implement a callback that verifies if the object and its properties are of expected type (don't blacklist, use whitelist!):
```cs
class LimitedBinder : SerializationBinder
{
    List<Type> allowedTypes = new List<Type>()
    {
        typeof(Exception),
        typeof(List<Exception>),
    };

    public override Type BindToType(string assemblyName, string typeName)
    {
        var type = Type.GetType(String.Format("{0}, {1}", typeName, assemblyName), true);
        foreach(Type allowedType in allowedTypes)
        {
            if(type == allowedType)
                return allowedType;
        }

        // Don’t return null for unexpected types –
        // this makes some serializers fall back to a default binder, allowing exploits.
        throw new Exception("Unexpected serialized type");
    }
}

var formatter = new BinaryFormatter() { Binder = new LimitedBinder () };
var data = (List<Exception>)formatter.Deserialize (fs);
```
Determining which types are safe is quite difficult, and this approach is not recommended unless necessary. There are many types that might allow non Remote Code Execution exploits if they are deserialized from untrusted data. Denial of service is especially common. As an example, the System.Collections.HashTable class is not safe to deserialize from an untrusted stream – the stream can specify the size of the internal “bucket” array and cause an out of memory condition.  

4) Serialize simple [Data Transfer Objects (DTO)](https://en.wikipedia.org/wiki/Data_transfer_object) only. Do not serialize/deserialize type information. For example, use only `TypeNameHandling.None` (the default) in Json.net:
```cs
class DataForStorage
{
    public string Id;
    public int    Count;
}

var data = JsonConvert.SerializeObject<DataForStorage>(json, new
JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.None
});
```
will produce the following JSON without type information that is perfectly fine to deserialize back:
```json
{
  "Id": null,
  "Count": 0
}
```
#### References
[CWE-502: Deserialization of Untrusted Data](https://cwe.mitre.org/data/definitions/502.html)  
[BlackHat USA 2017: Friday the 13th: JSON Attacks](https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf)  
[BlueHat v17: Dangerous Contents - Securing .Net Deserialization](https://www.slideshare.net/MSbluehat/dangerous-contents-securing-net-deserialization)  
[BlackHat USA 2012: Are you my type?](https://media.blackhat.com/bh-us-12/Briefings/Forshaw/BH_US_12_Forshaw_Are_You_My_Type_Slides.pdf)  
[OWASP: Deserialization of untrusted data](https://www.owasp.org/index.php/Deserialization_of_untrusted_data)  
[Deserialization payload generator for a variety of .NET formatters](https://github.com/pwntester/ysoserial.net)  
[.NET Deserialization Passive Scanner](https://github.com/pwntester/dotnet-deserialization-scanner)  
