1+ import csharp
2+ import semmle.code.csharp.security.dataflow.flowsources.Remote
3+ import semmle.code.csharp.serialization.Deserializers
4+
5+ class BadTypeHandling extends Expr {
6+ BadTypeHandling ( ) {
7+ exists ( Enum e , EnumConstant c |
8+ e .hasFullyQualifiedName ( "Newtonsoft.Json" , "TypeNameHandling" ) and
9+ c = e .getAnEnumConstant ( ) and
10+ this = c .getAnAccess ( ) and
11+ not c .hasName ( "None" )
12+ ) or
13+ this .( IntegerLiteral ) .getValue ( ) .toInt ( ) > 0
14+ }
15+ }
16+
17+ class TypeNameHandlingProperty extends Property {
18+ TypeNameHandlingProperty ( ) {
19+ this .hasFullyQualifiedName ( "Newtonsoft.Json" , [ "JsonSerializerSettings" , "JsonSerializer" ] , "TypeNameHandling" )
20+ }
21+ }
22+
23+ class TypeNameHandlingPropertyWrite extends PropertyWrite {
24+ TypeNameHandlingPropertyWrite ( ) { this .getProperty ( ) instanceof TypeNameHandlingProperty }
25+
26+ Expr getAssignedValue ( ) {
27+ exists ( AssignExpr a |
28+ a .getLValue ( ) = this and
29+ result = a .getRValue ( )
30+ )
31+ }
32+ }
33+
34+ class BadTypeHandlingPropertyWrite extends TypeNameHandlingPropertyWrite {
35+ BadTypeHandlingPropertyWrite ( ) {
36+ exists ( BadTypeHandling b |
37+ DataFlow:: localExprFlow ( b , getAssignedValue ( ) )
38+ )
39+ }
40+ }
41+
42+ class BinderPropertyWrite extends PropertyWrite {
43+ BinderPropertyWrite ( ) {
44+ this .getProperty ( ) .hasFullyQualifiedName ( "Newtonsoft.Json" , [ "JsonSerializerSettings" , "JsonSerializer" ] , [ "SerializationBinder" , "Binder" ] )
45+ }
46+ }
47+
48+ module UserInputToDeserializeObjectCallConfig implements DataFlow:: ConfigSig {
49+ predicate isSource ( DataFlow:: Node source ) {
50+ source instanceof RemoteFlowSource
51+ }
52+
53+ predicate isSink ( DataFlow:: Node sink ) {
54+ exists ( MethodCall mc |
55+ mc .getTarget ( ) .hasFullyQualifiedName ( "Newtonsoft.Json.JsonConvert" , _) and
56+ mc .getTarget ( ) .hasUndecoratedName ( "DeserializeObject" ) and
57+ sink .asExpr ( ) = mc .getAnArgument ( )
58+ )
59+ }
60+ predicate isAdditionalFlowStep ( DataFlow:: Node pred , DataFlow:: Node succ ) {
61+ exists ( MethodCall ma |
62+ ma .getTarget ( ) .hasName ( "ToString" ) and
63+ ma .getQualifier ( ) = pred .asExpr ( ) and
64+ succ .asExpr ( ) = ma
65+ )
66+ }
67+ }
68+
69+ module UserInputToDeserializeObjectCallFlow = TaintTracking:: Global< UserInputToDeserializeObjectCallConfig > ;
70+
71+
72+ module UnsafeTypeNameHandlingFlowConfig implements DataFlow:: ConfigSig {
73+ predicate isSource ( DataFlow:: Node source ) {
74+ source .asExpr ( ) instanceof BadTypeHandling
75+ }
76+
77+ predicate isSink ( DataFlow:: Node sink ) {
78+ exists ( TypeNameHandlingPropertyWrite prop | sink = DataFlow:: exprNode ( prop .getAssignedValue ( ) ) )
79+ }
80+
81+ predicate isBarrierIn ( DataFlow:: Node node ) { isSource ( node ) }
82+ }
83+
84+ module UnsafeTypeNameHandlingFlow = DataFlow:: Global< UnsafeTypeNameHandlingFlowConfig > ;
85+
86+ /**
87+ * An ObjectCreation of type `Newtonson.Json.JsonSerializerSettings.JsonSerializerSettings` or `Newtonson.Json.JsonSerializerSettings.JsonSerializer`.
88+ */
89+ class JsonSerializerSettingsCreation extends ObjectCreation {
90+ JsonSerializerSettingsCreation ( ) {
91+ this .getTarget ( )
92+ .hasFullyQualifiedName ( "Newtonsoft.Json.JsonSerializerSettings" , "JsonSerializerSettings" ) or
93+ this .getTarget ( )
94+ .hasFullyQualifiedName ( "Newtonsoft.Json.JsonSerializer" , "JsonSerializer" )
95+ }
96+ Class getAssignedBinderType ( ) {
97+ exists ( AssignExpr ae |
98+ ae .getLValue ( ) = this .getBinderPropertyWrite ( ) and
99+ ae .getRValue ( ) .getType ( ) = result
100+ )
101+ }
102+
103+ BinderPropertyWrite getBinderPropertyWrite ( ) {
104+ result = this .getPropertyWrite ( )
105+ }
106+
107+ TypeNameHandlingPropertyWrite getTypeNameHandlingPropertyWrite ( ) {
108+ result = this .getPropertyWrite ( )
109+ }
110+
111+ PropertyWrite getPropertyWrite ( ) {
112+ result = this .getInitializer ( ) .getAChild * ( )
113+ or
114+ // Direct local flow via some intermediary
115+ DataFlow:: localExprFlow ( this , result .getQualifier ( ) )
116+ or
117+ // Local flow via property writes
118+ hasPropertyWrite ( result )
119+ }
120+
121+ /**
122+ * The qualifier to `pw` is a property, which this value flows into somewhere locally.
123+ * Janky local DF.
124+ * */
125+ bindingset [ pw]
126+ pragma [ inline_late]
127+ predicate hasPropertyWrite ( PropertyWrite pw ) {
128+ exists ( Assignment a |
129+ a .getRValue ( ) = this
130+ and a .getLValue ( ) .( PropertyAccess ) .getTarget ( ) = pw .getQualifier ( ) .( PropertyAccess ) .getTarget ( )
131+ and a .getEnclosingCallable ( ) = pw .getEnclosingCallable ( )
132+ )
133+ }
134+ }
0 commit comments