Refactor JsonpInjection

This commit is contained in:
Ed Minnix
2023-04-12 12:09:56 -04:00
parent 8cb5e78832
commit d48adbd175
3 changed files with 36 additions and 37 deletions

View File

@@ -1,7 +1,6 @@
import java import java
import semmle.code.java.dataflow.DataFlow import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.FlowSources import semmle.code.java.dataflow.FlowSources
import DataFlow::PathGraph
/** Json string type data. */ /** Json string type data. */
abstract class JsonStringSource extends DataFlow::Node { } abstract class JsonStringSource extends DataFlow::Node { }

View File

@@ -12,35 +12,37 @@
*/ */
import java import java
import JsonpInjectionLib import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.dataflow.FlowSources import semmle.code.java.dataflow.FlowSources
import semmle.code.java.deadcode.WebEntryPoints import semmle.code.java.deadcode.WebEntryPoints
import DataFlow::PathGraph import semmle.code.java.security.XSS
import JsonpInjectionLib
import RequestResponseFlow::PathGraph
/** Taint-tracking configuration tracing flow from get method request sources to output jsonp data. */ /** Taint-tracking configuration tracing flow from get method request sources to output jsonp data. */
class RequestResponseFlowConfig extends TaintTracking::Configuration { module RequestResponseFlowConfig implements DataFlow::ConfigSig {
RequestResponseFlowConfig() { this = "RequestResponseFlowConfig" } predicate isSource(DataFlow::Node source) {
override predicate isSource(DataFlow::Node source) {
source instanceof RemoteFlowSource and source instanceof RemoteFlowSource and
any(RequestGetMethod m).polyCalls*(source.getEnclosingCallable()) any(RequestGetMethod m).polyCalls*(source.getEnclosingCallable())
} }
override predicate isSink(DataFlow::Node sink) { predicate isSink(DataFlow::Node sink) {
sink instanceof XssSink and sink instanceof XssSink and
any(RequestGetMethod m).polyCalls*(sink.getEnclosingCallable()) any(RequestGetMethod m).polyCalls*(sink.getEnclosingCallable())
} }
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
exists(MethodAccess ma | exists(MethodAccess ma |
isRequestGetParamMethod(ma) and pred.asExpr() = ma.getQualifier() and succ.asExpr() = ma isRequestGetParamMethod(ma) and pred.asExpr() = ma.getQualifier() and succ.asExpr() = ma
) )
} }
} }
from DataFlow::PathNode source, DataFlow::PathNode sink, RequestResponseFlowConfig conf module RequestResponseFlow = TaintTracking::Global<RequestResponseFlowConfig>;
from RequestResponseFlow::PathNode source, RequestResponseFlow::PathNode sink
where where
conf.hasFlowPath(source, sink) and RequestResponseFlow::flowPath(source, sink) and
exists(JsonpInjectionFlowConfig jhfc | jhfc.hasFlowTo(sink.getNode())) JsonpInjectionFlow::flowTo(sink.getNode())
select sink.getNode(), source, sink, "Jsonp response might include code from $@.", source.getNode(), select sink.getNode(), source, sink, "Jsonp response might include code from $@.", source.getNode(),
"this user input" "this user input"

View File

@@ -1,11 +1,9 @@
import java import java
import DataFlow private import JsonStringLib
import JsonStringLib private import semmle.code.java.security.XSS
import semmle.code.java.security.XSS private import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.dataflow.DataFlow private import semmle.code.java.dataflow.FlowSources
import semmle.code.java.dataflow.DataFlow3 private import semmle.code.java.frameworks.spring.SpringController
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.frameworks.spring.SpringController
/** /**
* A method that is called to handle an HTTP GET request. * A method that is called to handle an HTTP GET request.
@@ -81,38 +79,38 @@ class JsonpBuilderExpr extends AddExpr {
} }
/** A data flow configuration tracing flow from remote sources to jsonp function name. */ /** A data flow configuration tracing flow from remote sources to jsonp function name. */
class RemoteFlowConfig extends DataFlow2::Configuration { module RemoteFlowConfig implements DataFlow::ConfigSig {
RemoteFlowConfig() { this = "RemoteFlowConfig" } predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource } predicate isSink(DataFlow::Node sink) {
override predicate isSink(DataFlow::Node sink) {
exists(JsonpBuilderExpr jhe | jhe.getFunctionName() = sink.asExpr()) exists(JsonpBuilderExpr jhe | jhe.getFunctionName() = sink.asExpr())
} }
} }
module RemoteFlow = DataFlow::Global<RemoteFlowConfig>;
/** A data flow configuration tracing flow from json data into the argument `json` of JSONP-like string `someFunctionName + "(" + json + ")"`. */ /** A data flow configuration tracing flow from json data into the argument `json` of JSONP-like string `someFunctionName + "(" + json + ")"`. */
class JsonDataFlowConfig extends DataFlow2::Configuration { module JsonDataFlowConfig implements DataFlow::ConfigSig {
JsonDataFlowConfig() { this = "JsonDataFlowConfig" } predicate isSource(DataFlow::Node src) { src instanceof JsonStringSource }
override predicate isSource(DataFlow::Node src) { src instanceof JsonStringSource } predicate isSink(DataFlow::Node sink) {
override predicate isSink(DataFlow::Node sink) {
exists(JsonpBuilderExpr jhe | jhe.getJsonExpr() = sink.asExpr()) exists(JsonpBuilderExpr jhe | jhe.getJsonExpr() = sink.asExpr())
} }
} }
/** Taint-tracking configuration tracing flow from probable jsonp data with a user-controlled function name to an outgoing HTTP entity. */ module JsonDataFlow = DataFlow::Global<JsonDataFlowConfig>;
class JsonpInjectionFlowConfig extends TaintTracking::Configuration {
JsonpInjectionFlowConfig() { this = "JsonpInjectionFlowConfig" }
override predicate isSource(DataFlow::Node src) { /** Taint-tracking configuration tracing flow from probable jsonp data with a user-controlled function name to an outgoing HTTP entity. */
exists(JsonpBuilderExpr jhe, JsonDataFlowConfig jdfc, RemoteFlowConfig rfc | module JsonpInjectionFlowConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node src) {
exists(JsonpBuilderExpr jhe |
jhe = src.asExpr() and jhe = src.asExpr() and
jdfc.hasFlowTo(DataFlow::exprNode(jhe.getJsonExpr())) and JsonDataFlow::flowTo(DataFlow::exprNode(jhe.getJsonExpr())) and
rfc.hasFlowTo(DataFlow::exprNode(jhe.getFunctionName())) RemoteFlow::flowTo(DataFlow::exprNode(jhe.getFunctionName()))
) )
} }
override predicate isSink(DataFlow::Node sink) { sink instanceof XssSink } predicate isSink(DataFlow::Node sink) { sink instanceof XssSink }
} }
module JsonpInjectionFlow = TaintTracking::Global<JsonpInjectionFlowConfig>;