@@ -32,227 +32,14 @@ module TaintedPath {
32
32
}
33
33
34
34
override predicate isBarrierGuard ( DataFlow:: BarrierGuardNode guard ) {
35
- guard instanceof StartsWithDotDotSanitizer or
36
- guard instanceof StartsWithDirSanitizer or
37
- guard instanceof IsAbsoluteSanitizer or
38
- guard instanceof ContainsDotDotSanitizer or
39
- guard instanceof RelativePathStartsWithSanitizer or
40
- guard instanceof IsInsideCheckSanitizer
35
+ guard instanceof BarrierGuardNode
41
36
}
42
37
43
38
override predicate isAdditionalFlowStep (
44
39
DataFlow:: Node src , DataFlow:: Node dst , DataFlow:: FlowLabel srclabel ,
45
40
DataFlow:: FlowLabel dstlabel
46
41
) {
47
- isTaintedPathStep ( src , dst , srclabel , dstlabel )
48
- or
49
- // Ignore all preliminary sanitization after decoding URI components
50
- srclabel instanceof Label:: PosixPath and
51
- dstlabel instanceof Label:: PosixPath and
52
- (
53
- any ( UriLibraryStep step ) .step ( src , dst )
54
- or
55
- exists ( DataFlow:: CallNode decode |
56
- decode .getCalleeName ( ) = "decodeURIComponent" or decode .getCalleeName ( ) = "decodeURI"
57
- |
58
- src = decode .getArgument ( 0 ) and
59
- dst = decode
60
- )
61
- )
62
- or
63
- promiseTaintStep ( src , dst ) and srclabel = dstlabel
64
- or
65
- any ( TaintTracking:: PersistentStorageTaintStep st ) .step ( src , dst ) and srclabel = dstlabel
66
- or
67
- exists ( DataFlow:: PropRead read | read = dst |
68
- src = read .getBase ( ) and
69
- read .getPropertyName ( ) != "length" and
70
- srclabel = dstlabel
71
- )
72
- or
73
- // string method calls of interest
74
- exists ( DataFlow:: MethodCallNode mcn , string name |
75
- srclabel = dstlabel and dst = mcn and mcn .calls ( src , name )
76
- |
77
- exists ( string substringMethodName |
78
- substringMethodName = "substr" or
79
- substringMethodName = "substring" or
80
- substringMethodName = "slice"
81
- |
82
- name = substringMethodName and
83
- // to avoid very dynamic transformations, require at least one fixed index
84
- exists ( mcn .getAnArgument ( ) .asExpr ( ) .getIntValue ( ) )
85
- )
86
- or
87
- exists ( string argumentlessMethodName |
88
- argumentlessMethodName = "toLocaleLowerCase" or
89
- argumentlessMethodName = "toLocaleUpperCase" or
90
- argumentlessMethodName = "toLowerCase" or
91
- argumentlessMethodName = "toUpperCase" or
92
- argumentlessMethodName = "trim" or
93
- argumentlessMethodName = "trimLeft" or
94
- argumentlessMethodName = "trimRight"
95
- |
96
- name = argumentlessMethodName
97
- )
98
- )
99
- or
100
- // A `str.split()` call can either split into path elements (`str.split("/")`) or split by some other string.
101
- exists ( StringSplitCall mcn | dst = mcn and mcn .getBaseString ( ) = src |
102
- if mcn .getSeparator ( ) = "/"
103
- then
104
- srclabel .( Label:: PosixPath ) .canContainDotDotSlash ( ) and
105
- dstlabel instanceof Label:: SplitPath
106
- else srclabel = dstlabel
107
- )
108
- or
109
- // array method calls of interest
110
- exists ( DataFlow:: MethodCallNode mcn , string name | dst = mcn and mcn .calls ( src , name ) |
111
- (
112
- name = "pop" or
113
- name = "shift"
114
- ) and
115
- srclabel instanceof Label:: SplitPath and
116
- dstlabel .( Label:: PosixPath ) .canContainDotDotSlash ( )
117
- or
118
- (
119
- name = "slice" or
120
- name = "splice" or
121
- name = "concat"
122
- ) and
123
- dstlabel instanceof Label:: SplitPath and
124
- srclabel instanceof Label:: SplitPath
125
- or
126
- name = "join" and
127
- mcn .getArgument ( 0 ) .mayHaveStringValue ( "/" ) and
128
- srclabel instanceof Label:: SplitPath and
129
- dstlabel .( Label:: PosixPath ) .canContainDotDotSlash ( )
130
- )
131
- or
132
- // prefix.concat(path)
133
- exists ( DataFlow:: MethodCallNode mcn |
134
- mcn .getMethodName ( ) = "concat" and mcn .getAnArgument ( ) = src
135
- |
136
- dst = mcn and
137
- dstlabel instanceof Label:: SplitPath and
138
- srclabel instanceof Label:: SplitPath
139
- )
140
- or
141
- // reading unknown property of split path
142
- exists ( DataFlow:: PropRead read | read = dst |
143
- src = read .getBase ( ) and
144
- not read .getPropertyName ( ) = "length" and
145
- not exists ( read .getPropertyNameExpr ( ) .getIntValue ( ) ) and
146
- // split[split.length - 1]
147
- not exists ( BinaryExpr binop |
148
- read .getPropertyNameExpr ( ) = binop and
149
- binop .getAnOperand ( ) .getIntValue ( ) = 1 and
150
- binop .getAnOperand ( ) .( PropAccess ) .getPropertyName ( ) = "length"
151
- ) and
152
- srclabel instanceof Label:: SplitPath and
153
- dstlabel .( Label:: PosixPath ) .canContainDotDotSlash ( )
154
- )
155
- }
156
-
157
- /**
158
- * Holds if we should include a step from `src -> dst` with labels `srclabel -> dstlabel`, and the
159
- * standard taint step `src -> dst` should be suppresesd.
160
- */
161
- predicate isTaintedPathStep (
162
- DataFlow:: Node src , DataFlow:: Node dst , Label:: PosixPath srclabel , Label:: PosixPath dstlabel
163
- ) {
164
- // path.normalize() and similar
165
- exists ( NormalizingPathCall call |
166
- src = call .getInput ( ) and
167
- dst = call .getOutput ( ) and
168
- dstlabel = srclabel .toNormalized ( )
169
- )
170
- or
171
- // path.resolve() and similar
172
- exists ( ResolvingPathCall call |
173
- src = call .getInput ( ) and
174
- dst = call .getOutput ( ) and
175
- dstlabel .isAbsolute ( ) and
176
- dstlabel .isNormalized ( )
177
- )
178
- or
179
- // path.relative() and similar
180
- exists ( NormalizingRelativePathCall call |
181
- src = call .getInput ( ) and
182
- dst = call .getOutput ( ) and
183
- dstlabel .isRelative ( ) and
184
- dstlabel .isNormalized ( )
185
- )
186
- or
187
- // path.dirname() and similar
188
- exists ( PreservingPathCall call |
189
- src = call .getInput ( ) and
190
- dst = call .getOutput ( ) and
191
- srclabel = dstlabel
192
- )
193
- or
194
- // foo.replace(/\./, "") and similar
195
- exists ( DotRemovingReplaceCall call |
196
- src = call .getInput ( ) and
197
- dst = call .getOutput ( ) and
198
- srclabel .isAbsolute ( ) and
199
- dstlabel .isAbsolute ( ) and
200
- dstlabel .isNormalized ( )
201
- )
202
- or
203
- // foo.replace(/(\.\.\/)*/, "") and similar
204
- exists ( DotDotSlashPrefixRemovingReplace call |
205
- src = call .getInput ( ) and
206
- dst = call .getOutput ( )
207
- |
208
- // the 4 possible combinations of normalized + relative for `srclabel`, and the possible values for `dstlabel` in each case.
209
- srclabel .isNonNormalized ( ) and srclabel .isRelative ( ) // raw + relative -> any()
210
- or
211
- srclabel .isNormalized ( ) and srclabel .isAbsolute ( ) and srclabel = dstlabel // normalized + absolute -> normalized + absolute
212
- or
213
- srclabel .isNonNormalized ( ) and srclabel .isAbsolute ( ) and dstlabel .isAbsolute ( ) // raw + absolute -> raw/normalized + absolute
214
- // normalized + relative -> none()
215
- )
216
- or
217
- // path.join()
218
- exists ( DataFlow:: CallNode join , int n |
219
- join = NodeJSLib:: Path:: moduleMember ( "join" ) .getACall ( )
220
- |
221
- src = join .getArgument ( n ) and
222
- dst = join and
223
- (
224
- // If the initial argument is tainted, just normalize it. It can be relative or absolute.
225
- n = 0 and
226
- dstlabel = srclabel .toNormalized ( )
227
- or
228
- // For later arguments, the flow label depends on whether the first argument is absolute or relative.
229
- // If in doubt, we assume it is absolute.
230
- n > 0 and
231
- srclabel .canContainDotDotSlash ( ) and
232
- dstlabel .isNormalized ( ) and
233
- if isRelative ( join .getArgument ( 0 ) .getStringValue ( ) )
234
- then dstlabel .isRelative ( )
235
- else dstlabel .isAbsolute ( )
236
- )
237
- )
238
- or
239
- // String concatenation - behaves like path.join() except without normalization
240
- exists ( DataFlow:: Node operator , int n |
241
- StringConcatenation:: taintStep ( src , dst , operator , n )
242
- |
243
- // use ordinary taint flow for the first operand
244
- n = 0 and
245
- srclabel = dstlabel
246
- or
247
- n > 0 and
248
- srclabel .canContainDotDotSlash ( ) and
249
- dstlabel .isNonNormalized ( ) and // The ../ is no longer at the beginning of the string.
250
- (
251
- if isRelative ( StringConcatenation:: getOperand ( operator , 0 ) .getStringValue ( ) )
252
- then dstlabel .isRelative ( )
253
- else dstlabel .isAbsolute ( )
254
- )
255
- )
42
+ isAdditionalTaintedPathFlowStep ( src , dst , srclabel , dstlabel )
256
43
}
257
44
}
258
45
}
0 commit comments