Skip to content

Commit 8df7b7c

Browse files
authored
Merge pull request github#3525 from erik-krogh/ZipTaint
Approved by asgerf
2 parents 079021a + a23cde1 commit 8df7b7c

File tree

7 files changed

+322
-278
lines changed

7 files changed

+322
-278
lines changed

javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ module NodeJSLib {
279279
DataFlow::Node tainted;
280280

281281
PathFlowTarget() {
282-
exists(string methodName | this = DataFlow::moduleMember("path", methodName).getACall() |
282+
exists(string methodName | this = NodeJSLib::Path::moduleMember(methodName).getACall() |
283283
// getters
284284
methodName = "basename" and tainted = getArgument(0)
285285
or

javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll

Lines changed: 2 additions & 215 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)