JS: extract PrintfStyleCall out of TaintedFormatString

This commit is contained in:
Esben Sparre Andreasen
2018-08-20 10:10:25 +02:00
parent e1f3637b66
commit c058b91587
3 changed files with 98 additions and 50 deletions

View File

@@ -66,6 +66,7 @@ import semmle.javascript.frameworks.React
import semmle.javascript.frameworks.ReactNative
import semmle.javascript.frameworks.Request
import semmle.javascript.frameworks.SQL
import semmle.javascript.frameworks.StringFormatters
import semmle.javascript.frameworks.UriLibraries
import semmle.javascript.frameworks.XmlParsers
import semmle.javascript.frameworks.xUnit

View File

@@ -0,0 +1,94 @@
/**
* Provides classes for modeling string formatting libraries.
*/
import javascript
/**
* A printf-style call that substitutes the embedded format specifiers of a format string for the format arguments.
*/
abstract class PrintfStyleCall extends DataFlow::CallNode {
/**
* Gets the format string.
*/
abstract DataFlow::Node getFormatString();
/**
* Gets the ith argument to the format string.
*/
abstract DataFlow::Node getFormatArgument(int i);
}
private class LibraryFormatter extends PrintfStyleCall {
int formatIndex;
LibraryFormatter() {
// built-in Node.js functions
exists (string mod, string meth |
mod = "console" and (
(
meth = "debug" or
meth = "error" or
meth = "info" or
meth = "log" or
meth = "trace" or
meth = "warn"
) and
formatIndex = 0
or
meth = "assert" and formatIndex = 1
)
or
mod = "util" and (
(meth = "format" or meth = "log") and formatIndex = 0
or
meth = "formatWithOptions" and formatIndex = 1
)
|
// `console` and `util` are available both as modules...
this = DataFlow::moduleMember(mod, meth).getACall()
or
// ...and as globals
this = DataFlow::globalVarRef(mod).getAMemberCall(meth)
)
or
(
// https://www.npmjs.com/package/printf
this = DataFlow::moduleImport("printf").getACall() and
formatIndex in [0..1]
or
// https://www.npmjs.com/package/printj
exists (string fn | fn = "sprintf" or fn = "vsprintf" |
this = DataFlow::moduleMember("printj", fn).getACall() and
formatIndex = 0
)
or
// https://www.npmjs.com/package/format-util
this = DataFlow::moduleImport("format-util").getACall() and
formatIndex = 0
or
// https://www.npmjs.com/package/string-template
this = DataFlow::moduleImport("string-template").getACall() and
formatIndex = 0
or
this = DataFlow::moduleImport("string-template/compile").getACall() and
formatIndex = 0
or
// https://www.npmjs.com/package/sprintf-js
exists (string meth | meth = "sprintf" or meth = "vsprintf" |
this = DataFlow::moduleMember("sprintf-js", meth).getACall() and
formatIndex = 0
)
)
}
override DataFlow::Node getFormatString() {
result = getArgument(formatIndex)
}
override DataFlow::Node getFormatArgument(int i) {
i >= 0 and
result = getArgument(formatIndex + 1 + i)
}
}

View File

@@ -58,57 +58,10 @@ module TaintedFormatString {
*/
class FormatSink extends Sink {
FormatSink() {
exists (DataFlow::CallNode call, int argIdx |
// built-in Node.js functions
exists (string mod, string meth |
mod = "console" and
(meth = "debug" or meth = "error" or meth = "info" or
meth = "log" or meth = "trace" or meth = "warn") and
argIdx = 0
or
mod = "console" and meth = "assert" and argIdx = 1
or
mod = "util" and (meth = "format" or meth = "log") and argIdx = 0
or
mod = "util" and meth = "formatWithOptions" and argIdx = 1
|
// `console` and `util` are available both as modules...
call = DataFlow::moduleMember(mod, meth).getACall()
or
// ...and as globals
call = DataFlow::globalVarRef(mod).getAMemberCall(meth)
)
or
// https://www.npmjs.com/package/printf
call = DataFlow::moduleImport("printf").getACall() and
argIdx in [0..1]
or
// https://www.npmjs.com/package/printj
exists (string fn | fn = "sprintf" or fn = "vsprintf" |
call = DataFlow::moduleMember("printj", fn).getACall() and
argIdx = 0
)
or
// https://www.npmjs.com/package/format-util
call = DataFlow::moduleImport("format-util").getACall() and
argIdx = 0
or
// https://www.npmjs.com/package/string-template
call = DataFlow::moduleImport("string-template").getACall() and
argIdx = 0
or
call = DataFlow::moduleImport("string-template/compile").getACall() and
argIdx = 0
or
// https://www.npmjs.com/package/sprintf-js
exists (string meth | meth = "sprintf" or meth = "vsprintf" |
call = DataFlow::moduleMember("sprintf-js", meth).getACall() and
argIdx = 0
)
|
this = call.getArgument(argIdx) and
exists(PrintfStyleCall printf |
this = printf.getFormatString() and
// exclude trivial case where there are no arguments to interpolate
exists(call.getArgument(argIdx+1))
exists(printf.getFormatArgument(_))
)
}
}