Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
ac29184
deserialization sinks
Mar 8, 2021
94234b8
Rename ObjectMethodSink to InstanceMethodSink
Mar 31, 2021
8bb3be2
Fix comment
Mar 31, 2021
7cbbd6c
Simplify query
Mar 31, 2021
aa9d848
Rename taint tracking variables
Mar 31, 2021
f8867e4
Rename deserializeCall to deserializeCallArg
Mar 31, 2021
1308070
Make query symmetric
Mar 31, 2021
a4fd70a
Use don't care expression
Apr 14, 2021
3a9d1f4
Hide implementation details
Apr 14, 2021
b027fdd
Remove redundant check
Apr 14, 2021
1581a27
Simplify getTarget check
Apr 15, 2021
773556e
Use hasFlow where path is not needed
Apr 15, 2021
3aedd2c
Use TaintTracking2
Apr 15, 2021
a412581
reintroduce UnsafeDeserializer
Apr 15, 2021
c3deb48
Charpred for InstanceMethodSink
Apr 16, 2021
3ac5f7b
Move RemoteSource and LocalSource to UnsafeDeserialization.qll
Apr 21, 2021
0590522
a deserializer
Apr 21, 2021
8f6411d
Simpify with exists
Apr 21, 2021
9cc67e4
make private where possible
Apr 21, 2021
b6952d5
get rid of getParent
Apr 21, 2021
8084449
Get rid of UnsafeDeserializerCallable
Apr 21, 2021
9e46ef3
Get rid of getParent
Apr 21, 2021
a93d6a3
Remove SafeConstructorTrackingConfig
Apr 21, 2021
57689df
Remove DataFlow::Node
Apr 21, 2021
c9c9758
Make similarly named files in tests and qhelp in sync
Apr 22, 2021
18a3e4d
add comments
Apr 27, 2021
1682e99
Merge with Main
Jul 12, 2021
c3ac3ca
FsPickler
Jun 14, 2021
1e4409f
SharpSerializer
Jun 14, 2021
f4cb6c5
YamlDotNet
Jun 15, 2021
a0942e0
JsonConvert
Jul 12, 2021
fd4d8e2
Use HasFlow instead HasFlowPath
Jul 14, 2021
d1e4168
Merge with main
Aug 4, 2021
db2f9ad
Post merge
Aug 4, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,17 @@ it may be necessary to use a different deserialization framework.</p>

<sample src="UnsafeDeserializationUntrustedInputGood.cs" />

<p>In the following example potentially untrusted stream and type is deserialized using a
<code>DataContractJsonSerializer</code> which is known to be vulnerable with user supplied types.</p>

<sample src="UnsafeDeserializationUntrustedInputTypeBad.cs" />

<p>To fix this specific vulnerability, we are using hardcoded
Plain Old CLR Object (<a href="https://en.wikipedia.org/wiki/Plain_old_CLR_object">POCO</a>) type. In other cases,
it may be necessary to use a different deserialization framework.</p>

<sample src="UnsafeDeserializationUntrustedInputTypeGood.cs" />

</example>
<references>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,46 @@ import csharp
import semmle.code.csharp.security.dataflow.UnsafeDeserializationQuery
import DataFlow::PathGraph

from TaintTrackingConfig config, DataFlow::PathNode source, DataFlow::PathNode sink
where config.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "$@ flows to unsafe deserializer.", source.getNode(),
"User-provided data"
from DataFlow::PathNode userInput, DataFlow::PathNode deserializeCallArg
where
exists(TaintToObjectMethodTrackingConfig taintTracking |
// all flows from user input to deserialization with weak and strong type serializers
taintTracking.hasFlowPath(userInput, deserializeCallArg)
) and
// intersect with strong types, but user controlled or weak types deserialization usages
(
exists(
DataFlow::Node weakTypeCreation, DataFlow::Node weakTypeUsage,
WeakTypeCreationToUsageTrackingConfig weakTypeDeserializerTracking, MethodCall mc
|
weakTypeDeserializerTracking.hasFlow(weakTypeCreation, weakTypeUsage) and
mc.getQualifier() = weakTypeUsage.asExpr() and
mc.getAnArgument() = deserializeCallArg.getNode().asExpr()
)
or
exists(
TaintToObjectTypeTrackingConfig userControlledTypeTracking, DataFlow::Node taintedTypeUsage,
DataFlow::Node userInput2, MethodCall mc
|
userControlledTypeTracking.hasFlow(userInput2, taintedTypeUsage) and
mc.getQualifier() = taintedTypeUsage.asExpr() and
mc.getAnArgument() = deserializeCallArg.getNode().asExpr()
)
)
or
// no type check needed - straightforward taint -> sink
exists(TaintToConstructorOrStaticMethodTrackingConfig taintTracking2 |
taintTracking2.hasFlowPath(userInput, deserializeCallArg)
)
or
// JsonConvert static method call, but with additional unsafe typename tracking
exists(
JsonConvertTrackingConfig taintTrackingJsonConvert, TypeNameTrackingConfig typenameTracking,
DataFlow::Node settingsCallArg
|
taintTrackingJsonConvert.hasFlowPath(userInput, deserializeCallArg) and
typenameTracking.hasFlow(_, settingsCallArg) and
deserializeCallArg.getNode().asExpr().getParent() = settingsCallArg.asExpr().getParent()
)
select deserializeCallArg, userInput, deserializeCallArg, "$@ flows to unsafe deserializer.",
userInput, "User-provided data"
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class Good
public static object Deserialize(TextBox textBox)
{
JavaScriptSerializer sr = new JavaScriptSerializer();
// GOOD
// GOOD: no unsafe type resolver
return sr.DeserializeObject(textBox.Text);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System.Runtime.Serialization.Json;
using System.IO;
using System;

class BadDataContractJsonSerializer
{
public static object Deserialize(string type, Stream s)
{
// BAD: stream and type are potentially untrusted
var ds = new DataContractJsonSerializer(Type.GetType(type));
return ds.ReadObject(s);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System.Runtime.Serialization.Json;
using System.IO;
using System;

class Poco
{
public int Count;

public string Comment;
}

class GoodDataContractJsonSerializer
{
public static Poco Deserialize(Stream s)
{
// GOOD: while stream is potentially untrusted, the instantiated type is hardcoded
var ds = new DataContractJsonSerializer(typeof(Poco));
return (Poco)ds.ReadObject(s);
}
}
13 changes: 13 additions & 0 deletions csharp/ql/src/semmle/code/csharp/frameworks/JsonNET.qll
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,19 @@ module JsonNET {
JsonClass() { this.getParent() instanceof JsonNETNamespace }
}

/** Newtonsoft.Json.TypeNameHandling enum */
class TypeNameHandlingEnum extends Enum {
TypeNameHandlingEnum() {
this.getParent() instanceof JsonNETNamespace and
this.hasName("TypeNameHandling")
}
}

/** Newtonsoft.Json.JsonSerializerSettings class */
class JsonSerializerSettingsClass extends JsonClass {
JsonSerializerSettingsClass() { this.hasName("JsonSerializerSettings") }
}

/** The class `Newtonsoft.Json.JsonConvert`. */
class JsonConvertClass extends JsonClass, LibraryTypeDataFlow {
JsonConvertClass() { this.hasName("JsonConvert") }
Expand Down
Loading