@@ -32,227 +32,14 @@ module TaintedPath {
3232 }
3333
3434 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
4136 }
4237
4338 override predicate isAdditionalFlowStep (
4439 DataFlow:: Node src , DataFlow:: Node dst , DataFlow:: FlowLabel srclabel ,
4540 DataFlow:: FlowLabel dstlabel
4641 ) {
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 )
25643 }
25744 }
25845}
0 commit comments