Uploaded image for project: 'Product Roadmaps'
  1. Product Roadmaps
  2. MMF-2006

SonarC# and SonarSecurity detect C# deserialization vulnerabilities

    Details

    • Type: EPIC
    • Status: Resolved
    • Priority: Major
    • Resolution: Fixed
    • Fix Version/s: None
    • Labels:

      Description

      WHY

      Deserialization vulnerabilities often occur during development as spotted by these standards and metrics:

      Most of the CVEs have high impact (high CVSS score) because these vulnerabilities can lead to remote code execution (RCE) so it makes a lot of sense helping developers to protect against thoses.

      WHAT

      Use Cases

      When does this vulnerability occur?

      During deserialization

      A serialized object contains only data/"metadata" of the object, not the code, and deserialization libraries will reconstruct the state of an object by assigning data to properties with "magic methods" like readObject().

      Attackers will use these methods to find a chain of method calls (a gadget: object(s) available(s) in the assembly path) to execute arbitrary dangerous code:

      readObject() {
        doSomething1()
      }
      
      doSomething1() {
       execute() 
      }
      
      execute() {
       process(this.cmd); // RCE
      }
      

      ysoserial.net project maintains a list of gadgets to exploit these vulnerabilities:

      Not all gadgets are listed above, for instance, TempFileCollection is a well-known gadget used here:

      TempFileCollection.finalize() will be called by the garbage collector and delete arbitrary files specified in a serialized-object controlled by an attacker. We will use mainly this gadget in our code examples.

      After deserialization
      Another kind of problems might happen after the deserialization like "runtime bypasses".
      During the deserialization an object will be reconstructed without the constructor called (most of the times) thus it can break the data validation logic implemented in constructors:

      [Serializable]
      public class ExpectedSafeSerializedClass : IDeserializationCallback
      {
        public string _cmd;
            
        public ExpectedSafeSerializedClass(string cmd) { // Sensitive
           if(cmd != "echo") // Echo is the only cmd authorized
               throw new ArgumentException();
                
            _cmd = cmd;
         }
      }
      

      How to protect?

      During deserialization
      type of objects allowed to be reconstructed should be verified against a whitelist/blacklist:

      sealed class CustomBinder : SerializationBinder
      {
          public override Type BindToType(string assemblyName, string typeName)
          {
              if (!(typeName == "type1" || typeName == "type2"))
              {
                 throw new SerializationException("ExpectedSerializedClass type is expected"); // Compliant
              }
      
              return Assembly.Load(assemblyName).GetType(typeName);
          }
      }
      

      After deserialization
      Implement IDeserializationCallback or Iserialization and check the data against the expected validation logic after the deserialization.
      Example of code for a IDeserializationCallback type:

      void IDeserializationCallback.OnDeserialization(object sender) // Compliant
      {
        if(_cmd != "echo")
           throw new ArgumentException();
      }
      

      Default protection starting .NET 5.0

      A new API (Serialization Guard) to protect against deserialization has been implemented and will be shipped with .NET 5.0 (November 2020), it is not clear if this API will be:

      • enabled by default
      • target only .NET framework 5.0 or .NET core too

      Not all serializers will be protected with this API and limiting types allowed to be deserialized is always a good development practice (new gadgets can be found etc) whether this API is used or not. However, an update of our rules about deserialization should be performed when .NET framework 5.0 will be released.

      Comparison with other analyzers

      During deserialization

      xxxxxxxx security code scan roslyn-analyzer SonarDotnet Semmle
      BinaryFormatter SCS0028 CA2300 sonar-dotnet/issues/3282 QL1
      DataContractSerializer SCS0028 X X X
      XmlSerializer SCS0028 X SONARSEC-833 X
      LosFormatter SCS0028 CA2305 sonar-dotnet/issues/3282 X
      NetDataContractSerializer SCS0028 CA2310 sonar-dotnet/issues/3282 X
      ObjectStateFormatter SCS0028 CA2315 sonar-dotnet/issues/3282 X
      SoapFormatter SCS0028 X sonar-dotnet/issues/3282 X
      JavaScriptSerializer X CA2321 sonar-dotnet/issues/3282 QL2
      JsonSerializer X X X X
      Newton.JsonSerializer SCS0028 CA2327 X X
      XmlObjectSerializer SCS0028 X X X
      DataContractJsonSerializer SCS0028 X X X
      FastJSON SCS0028 X X X
      ServiceStack SCS0028 X X X

      After deserialization

      xxxxxxxx security code scan roslyn-analyzer SonarDotnet Semmle
      ISerializable X CA2229 sonar-dotnet/issues/3283 X
      IDeserializationCallback X X sonar-dotnet/issues/3283 X

      These serializers are "always" safe:

      • DataContractSerializer because expected types during deserialization should be explicitely defined.
      • XmlSerializer unless expected type is dynamically provided to the constructor and user-controlled.
      • JsonSerializer supports only basic types so it's safe.

      Out of scope of this MMF

      Should be specified later:

      • review/validation of these two rules already implemented covering other cases:
        • (code smell) RSPEC-3925 ("ISerializable" should be implemented correctly)
        • (vulnerability) RSPEC-4212: Serialization constructors should be secured (seems cover some patterns for "after deserialization" rule).

      Solution

      Two vulnerabilities and one security-hotspot:

      • SonarSecurity: RSPEC-5135: Deserialization should not be vulnerable to injection attacks
      • SonarC#: RSPEC-5766: Deserializing objects without performing data validation is security-sensitive
      • SonarC#: RSPEC-5773: Types allowed to be deserialized should be restricted

      The goal of serialization/deserialization is to exchange objects through applications thus most of the time serialized objects can be controlled by attackers, thus these rules should live as security-rules.

      Patterns to detect

      During deserialization
      See https://github.com/SonarSource/sonar-dotnet/issues/3282
      See https://jira.sonarsource.com/browse/SONARSEC-833

      After deserialization
      See https://github.com/SonarSource/sonar-dotnet/issues/3283

      SonarC# vs SonarSecurity

      • SonarC# will be used to detect C# misconfigured libraries:
        • when every types are resolved/deserialized or constructors validation logic can be bypassed
          • injection attacks or not, these misconfigurations can lead to at least unexpected runtime errors.
      • SonarSecurity will be used to detect C# libraries used in a way that are vulnerable to injection attacks without a doubt
        • for example when the type to deserialize is dynamically controlled by the attacker.

      HOW

      MMF-2063 and MMF-2064.

        Attachments

          Issue Links

            Activity

              People

              • Assignee:
                andrei.epure Andrei Epure
                Reporter:
                alexandre.gigleux Alexandre Gigleux
              • Votes:
                0 Vote for this issue
                Watchers:
                2 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved: