88 */
99
1010import csharp
11+ import semmle.code.csharp.dataflow.DataFlow2
1112import semmle.code.csharp.dataflow.TaintTracking
13+ import semmle.code.csharp.dataflow.TaintTracking2
1214import DataFlow:: PathGraph
1315
1416/** The C# class `Windows.Security.Cryptography.Core.HashAlgorithmProvider`. */
@@ -23,6 +25,13 @@ class HashAlgorithm extends RefType {
2325 HashAlgorithm ( ) { this .hasQualifiedName ( "System.Security.Cryptography" , "HashAlgorithm" ) }
2426}
2527
28+ /** The C# class `System.Security.Cryptography.KeyedHashAlgorithm`. */
29+ class KeyedHashAlgorithm extends RefType {
30+ KeyedHashAlgorithm ( ) {
31+ this .hasQualifiedName ( "System.Security.Cryptography" , "KeyedHashAlgorithm" )
32+ }
33+ }
34+
2635/**
2736 * The method `ComputeHash()` declared in `System.Security.Cryptography.HashAlgorithm` and
2837 * the method `HashData()` declared in `Windows.Security.Cryptography.Core.HashAlgorithmProvider`.
@@ -47,6 +56,20 @@ class PasswordVarExpr extends Expr {
4756 }
4857}
4958
59+ /** Holds if there is another hashing method call. */
60+ predicate hasAnotherHashCall ( MethodCall mc ) {
61+ exists ( Call mc2 , DataFlow2:: Node src , DataFlow2:: Node sink |
62+ (
63+ mc2 .getTarget ( ) instanceof HashMethod or
64+ mc2 .( ObjectCreation ) .getObjectType ( ) .getABaseType + ( ) instanceof HashAlgorithm
65+ ) and
66+ mc2 != mc and
67+ src .asExpr ( ) = mc .getAReachableElement ( ) and
68+ sink .asExpr ( ) = mc2 .getAChildExpr ( ) and
69+ TaintTracking2:: localTaint ( src , sink )
70+ )
71+ }
72+
5073/** Taint configuration tracking flow from an expression whose name suggests it holds password data to a method call that generates a hash without a salt. */
5174class HashWithoutSaltConfiguration extends TaintTracking:: Configuration {
5275 HashWithoutSaltConfiguration ( ) { this = "HashWithoutSaltConfiguration" }
@@ -56,7 +79,8 @@ class HashWithoutSaltConfiguration extends TaintTracking::Configuration {
5679 override predicate isSink ( DataFlow:: Node sink ) {
5780 exists ( MethodCall mc |
5881 sink .asExpr ( ) = mc .getArgument ( 0 ) and
59- mc .getTarget ( ) instanceof HashMethod
82+ mc .getTarget ( ) instanceof HashMethod and
83+ not hasAnotherHashCall ( mc )
6084 )
6185 }
6286
@@ -71,7 +95,7 @@ class HashWithoutSaltConfiguration extends TaintTracking::Configuration {
7195 }
7296
7397 /**
74- * Holds if a password is concatenated with a salt then hashed together through the call `System.Array.CopyTo()`, for example,
98+ * Holds if a password is concatenated with a salt then hashed together through calls such as `System.Array.CopyTo()`, for example,
7599 * `byte[] rawSalted = new byte[passBytes.Length + salt.Length];`
76100 * `passBytes.CopyTo(rawSalted, 0);`
77101 * `salt.CopyTo(rawSalted, passBytes.Length);`
@@ -81,11 +105,27 @@ class HashWithoutSaltConfiguration extends TaintTracking::Configuration {
81105 override predicate isSanitizer ( DataFlow:: Node node ) {
82106 exists ( MethodCall mc |
83107 mc .getTarget ( ) .fromLibrary ( ) and
84- mc .getTarget ( ) .hasQualifiedName ( "System.Array" , "CopyTo" ) and
85- mc .getArgument ( 0 ) = node .asExpr ( )
86- ) // passBytes.CopyTo(rawSalted, 0)
108+ (
109+ mc .getTarget ( ) .hasQualifiedName ( "System.Array" , "CopyTo" ) or // passBytes.CopyTo(rawSalted, 0)
110+ mc .getTarget ( ) .hasQualifiedName ( "System.String" , "Concat" ) or // string.Concat(password, saltkey)
111+ mc .getTarget ( ) .hasQualifiedName ( "System.Buffer" , "BlockCopy" ) or // Buffer.BlockCopy(salt, 0, allBytes, 0, 20)
112+ mc .getTarget ( ) .hasQualifiedName ( "System.String" , "Format" ) // String.Format("{0}:{1}:{2}", username, salt, password)
113+ ) and
114+ mc .getAnArgument ( ) = node .asExpr ( )
115+ )
87116 or
88117 exists ( AddExpr e | node .asExpr ( ) = e .getAnOperand ( ) ) // password+salt
118+ or
119+ exists ( InterpolatedStringExpr e | node .asExpr ( ) = e .getAnInsert ( ) )
120+ or
121+ // a salt or key is included in subclasses of `KeyedHashAlgorithm`
122+ exists ( MethodCall mc , Assignment ass , ObjectCreation oc |
123+ ass .getRValue ( ) = oc and
124+ oc .getObjectType ( ) .getABaseType + ( ) instanceof KeyedHashAlgorithm and
125+ mc .getTarget ( ) instanceof HashMethod and
126+ ass .getLValue ( ) = mc .getQualifier ( ) .( VariableAccess ) .getTarget ( ) .getAnAccess ( ) and
127+ mc .getArgument ( 0 ) = node .asExpr ( )
128+ )
89129 }
90130}
91131
0 commit comments