8
8
*/
9
9
10
10
import csharp
11
+ import semmle.code.csharp.dataflow.DataFlow2
11
12
import semmle.code.csharp.dataflow.TaintTracking
13
+ import semmle.code.csharp.dataflow.TaintTracking2
12
14
import DataFlow:: PathGraph
13
15
14
16
/** The C# class `Windows.Security.Cryptography.Core.HashAlgorithmProvider`. */
@@ -23,6 +25,13 @@ class HashAlgorithm extends RefType {
23
25
HashAlgorithm ( ) { this .hasQualifiedName ( "System.Security.Cryptography" , "HashAlgorithm" ) }
24
26
}
25
27
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
+
26
35
/**
27
36
* The method `ComputeHash()` declared in `System.Security.Cryptography.HashAlgorithm` and
28
37
* the method `HashData()` declared in `Windows.Security.Cryptography.Core.HashAlgorithmProvider`.
@@ -47,6 +56,20 @@ class PasswordVarExpr extends Expr {
47
56
}
48
57
}
49
58
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
+
50
73
/** 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. */
51
74
class HashWithoutSaltConfiguration extends TaintTracking:: Configuration {
52
75
HashWithoutSaltConfiguration ( ) { this = "HashWithoutSaltConfiguration" }
@@ -56,7 +79,8 @@ class HashWithoutSaltConfiguration extends TaintTracking::Configuration {
56
79
override predicate isSink ( DataFlow:: Node sink ) {
57
80
exists ( MethodCall mc |
58
81
sink .asExpr ( ) = mc .getArgument ( 0 ) and
59
- mc .getTarget ( ) instanceof HashMethod
82
+ mc .getTarget ( ) instanceof HashMethod and
83
+ not hasAnotherHashCall ( mc )
60
84
)
61
85
}
62
86
@@ -71,7 +95,7 @@ class HashWithoutSaltConfiguration extends TaintTracking::Configuration {
71
95
}
72
96
73
97
/**
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,
75
99
* `byte[] rawSalted = new byte[passBytes.Length + salt.Length];`
76
100
* `passBytes.CopyTo(rawSalted, 0);`
77
101
* `salt.CopyTo(rawSalted, passBytes.Length);`
@@ -81,11 +105,27 @@ class HashWithoutSaltConfiguration extends TaintTracking::Configuration {
81
105
override predicate isSanitizer ( DataFlow:: Node node ) {
82
106
exists ( MethodCall mc |
83
107
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
+ )
87
116
or
88
117
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
+ )
89
129
}
90
130
}
91
131
0 commit comments