Merge pull request #3704 from asger-semmle/js/cve-serve

Approved by esbena
This commit is contained in:
semmle-qlci
2020-06-15 09:54:17 +01:00
committed by GitHub
8 changed files with 191 additions and 5 deletions

View File

@@ -576,6 +576,22 @@ module Bluebird {
override DataFlow::Node getArrayNode() { result = getArgument(0) }
}
/**
* An async function created using a call to `bluebird.coroutine`.
*/
class BluebirdCoroutineDefinition extends DataFlow::CallNode {
BluebirdCoroutineDefinition() { this = bluebird().getAMemberCall("coroutine") }
}
private class BluebirdCoroutineDefinitionAsPartialInvoke extends DataFlow::PartialInvokeNode::Range,
BluebirdCoroutineDefinition {
override DataFlow::SourceNode getBoundFunction(DataFlow::Node callback, int boundArgs) {
boundArgs = 0 and
callback = getArgument(0) and
result = this
}
}
}
/**

View File

@@ -2,6 +2,7 @@ import semmle.javascript.frameworks.Express
import semmle.javascript.frameworks.Hapi
import semmle.javascript.frameworks.Koa
import semmle.javascript.frameworks.NodeJSLib
import semmle.javascript.frameworks.Micro
import semmle.javascript.frameworks.Restify
import semmle.javascript.frameworks.Connect
import semmle.javascript.frameworks.Fastify

View File

@@ -0,0 +1,114 @@
/**
* Provides a model of the `micro` NPM package.
*/
private import javascript
private module Micro {
private import DataFlow
/**
* A node that should be interpreted as a route handler, to use as starting
* point for back-tracking.
*/
Node microRouteHandlerSink() {
result = moduleMember("micro", "run").getACall().getLastArgument()
or
result = moduleImport("micro").getACall().getArgument(0)
}
/** Gets a data flow node interpreted as a route handler. */
private DataFlow::SourceNode microRouteHandler(DataFlow::TypeBackTracker t) {
t.start() and
result = microRouteHandlerSink().getALocalSource()
or
exists(DataFlow::TypeBackTracker t2 | result = microRouteHandler(t2).backtrack(t2, t))
or
exists(DataFlow::CallNode transformer |
transformer = moduleImport("micro-compress").getACall()
or
transformer instanceof Bluebird::BluebirdCoroutineDefinition
|
microRouteHandler(t.continue()) = transformer and
result = transformer.getArgument(0).getALocalSource()
)
}
/** Gets a data flow node interpreted as a route handler. */
DataFlow::SourceNode microRouteHandler() {
result = microRouteHandler(DataFlow::TypeBackTracker::end())
}
/**
* A function passed to `micro` or `micro.run`.
*/
class MicroRouteHandler extends HTTP::Servers::StandardRouteHandler, DataFlow::FunctionNode {
MicroRouteHandler() { this = microRouteHandler().getAFunctionValue() }
}
class MicroRequestSource extends HTTP::Servers::RequestSource {
MicroRouteHandler h;
MicroRequestSource() { this = h.getParameter(0) }
override HTTP::RouteHandler getRouteHandler() { result = h }
}
class MicroResponseSource extends HTTP::Servers::ResponseSource {
MicroRouteHandler h;
MicroResponseSource() { this = h.getParameter(1) }
override HTTP::RouteHandler getRouteHandler() { result = h }
}
class MicroRequestExpr extends NodeJSLib::RequestExpr {
override MicroRequestSource src;
}
class MicroReseponseExpr extends NodeJSLib::ResponseExpr {
override MicroResponseSource src;
}
private HTTP::RouteHandler getRouteHandlerFromReqRes(DataFlow::Node node) {
exists(HTTP::Servers::RequestSource src |
src.ref().flowsTo(node) and
result = src.getRouteHandler()
)
or
exists(HTTP::Servers::ResponseSource src |
src.ref().flowsTo(node) and
result = src.getRouteHandler()
)
}
class MicroBodyParserCall extends HTTP::RequestInputAccess, DataFlow::CallNode {
string name;
MicroBodyParserCall() {
name = ["buffer", "text", "json"] and
this = moduleMember("micro", name).getACall()
}
override string getKind() { result = "body" }
override HTTP::RouteHandler getRouteHandler() {
result = getRouteHandlerFromReqRes(getArgument(0))
}
override predicate isUserControlledObject() { name = "json" }
}
class MicroSendArgument extends HTTP::ResponseSendArgument {
CallNode send;
MicroSendArgument() {
send = moduleMember("micro", ["send", "sendError"]).getACall() and
this = send.getLastArgument().asExpr()
}
override HTTP::RouteHandler getRouteHandler() {
result = getRouteHandlerFromReqRes(send.getArgument([0, 1]))
}
}
}

View File

@@ -212,11 +212,10 @@ module TaintedPath {
DataFlow::Node output;
PreservingPathCall() {
exists(string name | name = "dirname" or name = "toNamespacedPath" |
this = NodeJSLib::Path::moduleMember(name).getACall() and
input = getAnArgument() and
output = this
)
this =
NodeJSLib::Path::moduleMember(["dirname", "toNamespacedPath", "parse", "format"]).getACall() and
input = getAnArgument() and
output = this
or
// non-global replace or replace of something other than /\.\./g, /[/]/g, or /[\.]/g.
this.getCalleeName() = "replace" and