89 lines
5.7 KiB
Plaintext
89 lines
5.7 KiB
Plaintext
Failure to control types during deserialization can lead to runtime errors and vulnerabilities. There are many types, called "gadgets" (see https://github.com/pwntester/ysoserial.net[ysoserial.net]) which are known to be not secure when deserializing.
|
|
|
|
During the deserialization process, the state of an object will be reconstructed from the serialized data stream which can contain dangerous operations. For example, a well-known attack vector consists in serializing an object of type <code>https://docs.microsoft.com/en-us/dotnet/api/system.codedom.compiler.tempfilecollection.-ctor?view=netframework-4.8#System_CodeDom_Compiler_TempFileCollection__ctor[TempFileCollection]</code> with arbitrary files defined by the attacker which will be deleted on the application deserializing this object (more precisely when the https://docs.microsoft.com/en-us/dotnet/api/system.codedom.compiler.tempfilecollection.finalize?view=netframework-4.8[finalize() ]method of the TempFileCollection object is called).
|
|
|
|
To restrict the types allowed to be deserialized:
|
|
|
|
* implement a whitelist of safe and required types that can be deserialized.
|
|
* or/and implement tamper protection, such as https://en.wikipedia.org/wiki/HMAC[message authentication codes] (MAC), this way only objects serialized with the correct MAC hash will be deserialized.
|
|
|
|
== Noncompliant Code Example
|
|
|
|
For https://docs.microsoft.com/en-us/dotnet/api/system.runtime.serialization.formatters.binary.binaryformatter?view=netframework-4.8[BinaryFormatter], https://docs.microsoft.com/en-us/dotnet/api/system.runtime.serialization.netdatacontractserializer?view=netframework-4.8[NetDataContractSerializer ], https://docs.microsoft.com/en-us/dotnet/api/system.runtime.serialization.formatters.soap.soapformatter?view=netframework-4.8[SoapFormatter] serializers:
|
|
|
|
----
|
|
var myBinaryFormatter = new BinaryFormatter();
|
|
myBinaryFormatter.Deserialize(stream); // Noncompliant: a binder is not used to limit types during deserialization
|
|
----
|
|
|
|
https://docs.microsoft.com/en-us/dotnet/api/system.web.script.serialization.javascriptserializer?view=netframework-4.8[JavaScriptSerializer] should not use SimpleTypeResolver or other weak resolvers:
|
|
|
|
----
|
|
JavaScriptSerializer serializer1 = new JavaScriptSerializer(new SimpleTypeResolver()); // Noncompliant: SimpleTypeResolver is unsecure (every types is resolved)
|
|
serializer1.Deserialize<ExpectedType>(json);
|
|
----
|
|
|
|
https://docs.microsoft.com/en-us/dotnet/api/system.web.ui.losformatter?view=netframework-4.8[LosFormatter] should not be used without MAC verification:
|
|
|
|
----
|
|
LosFormatter formatter = new LosFormatter(); // Noncompliant
|
|
formatter.Deserialize(fs);
|
|
----
|
|
|
|
== Compliant Solution
|
|
|
|
https://docs.microsoft.com/en-us/dotnet/api/system.runtime.serialization.formatters.binary.binaryformatter?view=netframework-4.8[BinaryFormatter], https://docs.microsoft.com/en-us/dotnet/api/system.runtime.serialization.netdatacontractserializer?view=netframework-4.8[NetDataContractSerializer ], https://docs.microsoft.com/en-us/dotnet/api/system.runtime.serialization.formatters.soap.soapformatter?view=netframework-4.8[SoapFormatter] serializers should use a binder implementing a whitelist approach to limit types during deserialization (at least one exception should be thrown or a null value returned):
|
|
|
|
----
|
|
sealed class CustomBinder : SerializationBinder
|
|
{
|
|
public override Type BindToType(string assemblyName, string typeName)
|
|
{
|
|
if (!(typeName == "type1" || typeName == "type2" || typeName == "type3"))
|
|
{
|
|
throw new SerializationException("Only type1, type2 and type3 are allowed"); // Compliant
|
|
}
|
|
return Assembly.Load(assemblyName).GetType(typeName);
|
|
}
|
|
}
|
|
|
|
var myBinaryFormatter = new BinaryFormatter();
|
|
myBinaryFormatter.Binder = new CustomBinder();
|
|
myBinaryFormatter.Deserialize(stream);
|
|
----
|
|
|
|
https://docs.microsoft.com/en-us/dotnet/api/system.web.script.serialization.javascriptserializer?view=netframework-4.8[JavaScriptSerializer] should use a resolver implementing a whitelist to limit types during deserialization (at least one exception should be thrown or a null value returned):
|
|
|
|
----
|
|
public class CustomSafeTypeResolver : JavaScriptTypeResolver
|
|
{
|
|
public override Type ResolveType(string id)
|
|
{
|
|
if(id != "ExpectedType") {
|
|
throw new ArgumentNullException("Only ExpectedType is allowed during deserialization"); // Compliant
|
|
}
|
|
return Type.GetType(id);
|
|
}
|
|
}
|
|
|
|
JavaScriptSerializer serializer = new JavaScriptSerializer(new CustomSafeTypeResolver()); // Compliant
|
|
serializer.Deserialize<ExpectedType>(json);
|
|
----
|
|
https://docs.microsoft.com/en-us/dotnet/api/system.web.ui.losformatter?view=netframework-4.8[LosFormatter] serializer with MAC verification:
|
|
|
|
----
|
|
LosFormatter formatter = new LosFormatter(true, secret); // Compliant
|
|
formatter.Deserialize(fs);
|
|
----
|
|
|
|
== See
|
|
|
|
* https://media.blackhat.com/bh-us-12/Briefings/Forshaw/BH_US_12_Forshaw_Are_You_My_Type_WP.pdf[Are You My Type?] - James Forshaw - BlackHat 2012
|
|
* https://www.youtube.com/watch?v=oxlD8VWWHE8[BlueHat v17 - Dangerous Contents - Securing .Net Deserialization]
|
|
* https://www.youtube.com/watch?v=qDoBlLwREYk0[Alvaro Muñoz: .NET Serialization: Detecting and Defending Vulnerable Endpoints]
|
|
* https://www.owasp.org/index.php/Top_10-2017_A8-Insecure_Deserialization[OWASP Top 10 2017 Category A8] - Insecure Deserialization
|
|
* https://cwe.mitre.org/data/definitions/134.html[MITRE, CWE-134] - Use of Externally-Controlled Format String
|
|
* https://cwe.mitre.org/data/definitions/502.html[MITRE, CWE-502] - Deserialization of Untrusted Data
|
|
* https://www.sans.org/top25-software-errors/#cat2[SANS Top 25] - Risky Resource Management
|
|
* https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Deserialization_Cheat_Sheet.md[OWASP Deserialization Cheat Sheet]
|