Added TaintPropagatingJexlMethodCall class

This commit is contained in:
Artem Smotrakov
2021-01-23 17:42:04 +01:00
parent 73c8338e52
commit 28ebbee61d

View File

@@ -8,6 +8,8 @@ import semmle.code.java.dataflow.TaintTracking
* It supports both Jexl2 and Jexl3.
*/
class JexlInjectionConfig extends TaintTracking::Configuration {
TaintPropagatingJexlMethodCall taintPropagatingJexlMethodCall;
JexlInjectionConfig() { this = "JexlInjectionConfig" }
override predicate isSource(DataFlow::Node source) {
@@ -18,12 +20,9 @@ class JexlInjectionConfig extends TaintTracking::Configuration {
override predicate isSink(DataFlow::Node sink) { sink instanceof JexlEvaluationSink }
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
createsJexlExpression(node1, node2) or
createsJexlTemplate(node1, node2) or
createsJexlScript(node1, node2) or
createsJexlCallable(node1, node2) or
returnsDataFromBean(node1, node2)
override predicate isAdditionalTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
taintPropagatingJexlMethodCall.taintFlow(fromNode, toNode) or
returnsDataFromBean(fromNode, toNode)
}
}
@@ -31,7 +30,7 @@ class JexlInjectionConfig extends TaintTracking::Configuration {
* A data flow source for parameters that have
* a Spring framework annotation indicating remote user input from servlets.
*/
class TaintedSpringRequestBody extends DataFlow::Node {
private class TaintedSpringRequestBody extends DataFlow::Node {
TaintedSpringRequestBody() {
exists(SpringServletInputAnnotation a | this.asParameter().getAnAnnotation() = a)
}
@@ -41,7 +40,7 @@ class TaintedSpringRequestBody extends DataFlow::Node {
* A sink for Expresssion Language injection vulnerabilities via Jexl,
* i.e. methods that run evaluation of a Jexl expression.
*/
class JexlEvaluationSink extends DataFlow::ExprNode {
private class JexlEvaluationSink extends DataFlow::ExprNode {
JexlEvaluationSink() {
isJexlExpressionEvaluationCall(asExpr()) or
isJexlTemplateEvaluationCall(asExpr()) or
@@ -52,89 +51,95 @@ class JexlEvaluationSink extends DataFlow::ExprNode {
}
/**
* Holds if `node1` to `node2` is a dataflow step that creates a Jexl expression.
* Defines method calls that propagate tainted data via one of the methods
* from Jexl library.
*/
predicate createsJexlExpression(DataFlow::Node node1, DataFlow::Node node2) {
exists(MethodAccess ma, Method m | ma.getMethod() = m |
(
m instanceof JxltEngineCreateExpressionMethod or
m instanceof UnifiedJexlParseMethod or
m instanceof JexlEngineCreateExpressionMethod
) and
ma.getAnArgument().getType() instanceof TypeString and
ma.getAnArgument() = node1.asExpr() and
node2.asExpr() = ma
)
private class TaintPropagatingJexlMethodCall extends MethodAccess {
string methodName;
RefType instanceType;
Expr taintFromExpr;
TaintPropagatingJexlMethodCall() {
exists(Method m |
this.getMethod() = m and
m.getDeclaringType() = instanceType and
m.hasName(methodName)
|
isMethodForCreatingJexlScript(instanceType, methodName) and
taintFromExpr = this.getArgument(0) and
taintFromExpr.getType() instanceof TypeString
or
isMethodForCreatingJexlCallable(instanceType, methodName) and
taintFromExpr = this.getQualifier()
or
isMethodForCreatingJexlExpression(instanceType, methodName) and
taintFromExpr = this.getAnArgument() and
taintFromExpr.getType() instanceof TypeString
or
isMethodForCreatingJexlTemplate(instanceType, methodName) and
(taintFromExpr.getType() instanceof TypeString or taintFromExpr.getType() instanceof Reader) and
taintFromExpr = this.getArgument([0, 1])
)
}
/**
* Holds if `fromNode` to `toNode` is a dataflow step that propagates
* tainted data.
*/
predicate taintFlow(DataFlow::Node fromNode, DataFlow::Node toNode) {
fromNode.asExpr() = taintFromExpr and toNode.asExpr() = this
}
}
/**
* Holds if `node1` to `node2` is a dataflow step that creates a Jexl template.
* Checks if `instanceType.methodName()` method creates a Jexl script.
*/
predicate createsJexlTemplate(DataFlow::Node node1, DataFlow::Node node2) {
exists(MethodAccess ma, Method m | ma.getMethod() = m |
(m instanceof JxltEngineCreateTemplateMethod or m instanceof UnifiedJexlCreateTemplateMethod) and
(
node1.asExpr().getType() instanceof TypeString or
node1.asExpr().getType() instanceof Reader
) and
ma.getArgument([0, 1]) = node1.asExpr() and
node2.asExpr() = ma
)
private predicate isMethodForCreatingJexlScript(RefType instanceType, string methodName) {
instanceType instanceof JexlEngine and methodName = "createScript"
}
/**
* Holds if:
* - `expr` is the `index`th argument to `ma`
* - `expr` is a string or an instance of `Reader`
* Checks if `instanceType.methodName()` method creates a `Callable` for a Jexl expression or script.
*/
predicate toberemoved(MethodAccess ma, int index, Expr expr) {
(
expr.getType() instanceof TypeString or
expr.getType() instanceof Reader
) and
ma.getArgument(index) = expr
private predicate isMethodForCreatingJexlCallable(RefType instanceType, string methodName) {
(instanceType instanceof JexlExpression or instanceType instanceof JexlScript) and
methodName = "callable"
}
/**
* Holds if `node1` to `node2` is a dataflow step that creates a Jexl script.
* Checks if `instanceType.methodName()` method creates a Jexl template.
*/
predicate createsJexlScript(DataFlow::Node node1, DataFlow::Node node2) {
exists(MethodAccess ma, Method m | ma.getMethod() = m |
m instanceof JexlEngineCreateScriptMethod and
ma.getArgument(0).getType() instanceof TypeString and
ma.getArgument(0) = node1.asExpr() and
node2.asExpr() = ma
)
private predicate isMethodForCreatingJexlTemplate(RefType instanceType, string methodName) {
(instanceType instanceof JxltEngine or instanceType instanceof UnifiedJexl) and
methodName = "createTemplate"
}
/**
* Holds if `node1` to `node2` is a dataflow step
* that creates a callable from a Jexl expression or script.
* Checks if `instanceType.methodName()` method creates a Jexl expression.
*/
predicate createsJexlCallable(DataFlow::Node node1, DataFlow::Node node2) {
exists(MethodAccess ma, Method m | ma.getMethod() = m |
(m instanceof JexlExpressionCallableMethod or m instanceof JexlScriptCallableMethod) and
ma.getQualifier() = node1.asExpr() and
node2.asExpr() = ma
)
private predicate isMethodForCreatingJexlExpression(RefType instanceType, string methodName) {
(instanceType instanceof JexlEngine or instanceType instanceof JxltEngine) and
methodName = "createExpression"
or
instanceType instanceof UnifiedJexl and methodName = "parse"
}
/**
* Holds if `node1` to `node2` is a dataflow step that returns data from
* Holds if `fromNode` to `toNode` is a dataflow step that returns data from
* a tainted bean by calling one of its getters.
*/
predicate returnsDataFromBean(DataFlow::Node node1, DataFlow::Node node2) {
private predicate returnsDataFromBean(DataFlow::Node fromNode, DataFlow::Node toNode) {
exists(MethodAccess ma, Method m | ma.getMethod() = m |
m instanceof GetterMethod and
ma.getQualifier() = node1.asExpr() and
ma = node2.asExpr()
ma.getQualifier() = fromNode.asExpr() and
ma = toNode.asExpr()
)
}
/**
* Holds if `expr` calls one of the methods that execute a Jexl script against qualifier `expr`.
*/
predicate isJexlScriptExecuteCall(Expr expr) {
private predicate isJexlScriptExecuteCall(Expr expr) {
exists(MethodAccess ma, Method m | m = ma.getMethod() |
m instanceof JexlScriptExecuteMethod and
ma.getQualifier() = expr
@@ -145,7 +150,7 @@ predicate isJexlScriptExecuteCall(Expr expr) {
* Holds if `expr` is the qualifier when calling the `Callable.call()` method
* such as `expr.call()`.
*/
predicate isCallableCall(Expr expr) {
private predicate isCallableCall(Expr expr) {
exists(MethodAccess ma, Method m | m = ma.getMethod() |
m instanceof CallableCallMethod and
ma.getQualifier() = expr
@@ -156,7 +161,7 @@ predicate isCallableCall(Expr expr) {
* Holds if `expr` is an argument in a call to one of the methods
* that get or set a property via a Jexl expression.
*/
predicate isJexlGetSetPropertyCall(Expr expr) {
private predicate isJexlGetSetPropertyCall(Expr expr) {
exists(MethodAccess ma, Method m | m = ma.getMethod() |
(m instanceof JexlEngineGetPropertyMethod or m instanceof JexlEngineSetPropertyMethod) and
ma.getAnArgument().getType() instanceof TypeString and
@@ -167,7 +172,7 @@ predicate isJexlGetSetPropertyCall(Expr expr) {
/**
* Holds if `expr` is a call to one of the methods that trigger evaluation of a Jexl expression.
*/
predicate isJexlExpressionEvaluationCall(Expr expr) {
private predicate isJexlExpressionEvaluationCall(Expr expr) {
exists(MethodAccess ma, Method m | m = ma.getMethod() |
(
m instanceof JexlExpressionEvaluateMethod or
@@ -183,7 +188,7 @@ predicate isJexlExpressionEvaluationCall(Expr expr) {
/**
* Holds if `expr` is a call to one of the methods that evaluates a Jexl template.
*/
predicate isJexlTemplateEvaluationCall(Expr expr) {
private predicate isJexlTemplateEvaluationCall(Expr expr) {
exists(MethodAccess ma, Method m | m = ma.getMethod() |
(
m instanceof JxltEngineTemplateEvaluateMethod or
@@ -194,9 +199,9 @@ predicate isJexlTemplateEvaluationCall(Expr expr) {
}
/**
* A method in the JexlExpression class that evaluates a Jexl expression.
* A method in the `JexlExpression` class that evaluates a Jexl expression.
*/
class JexlExpressionEvaluateMethod extends Method {
private class JexlExpressionEvaluateMethod extends Method {
JexlExpressionEvaluateMethod() {
getDeclaringType() instanceof JexlExpression and
hasName("evaluate")
@@ -204,19 +209,9 @@ class JexlExpressionEvaluateMethod extends Method {
}
/**
* A method in the JexlEngine class that creates a Jexl expression.
* A method in the `JexlEngine` class that gets a property with a Jexl expression.
*/
class JexlEngineCreateExpressionMethod extends Method {
JexlEngineCreateExpressionMethod() {
getDeclaringType() instanceof JexlEngine and
hasName("createExpression")
}
}
/**
* A method in the JexlEngine class that gets a property with a Jexl expression.
*/
class JexlEngineGetPropertyMethod extends Method {
private class JexlEngineGetPropertyMethod extends Method {
JexlEngineGetPropertyMethod() {
getDeclaringType() instanceof JexlEngine and
hasName("getProperty")
@@ -224,9 +219,9 @@ class JexlEngineGetPropertyMethod extends Method {
}
/**
* A method in the JexlEngine class that sets a property with a Jexl expression.
* A method in the `JexlEngine` class that sets a property with a Jexl expression.
*/
class JexlEngineSetPropertyMethod extends Method {
private class JexlEngineSetPropertyMethod extends Method {
JexlEngineSetPropertyMethod() {
getDeclaringType() instanceof JexlEngine and
hasName("setProperty")
@@ -234,19 +229,9 @@ class JexlEngineSetPropertyMethod extends Method {
}
/**
* A method in the JexlEngine class that creates a Jexl script.
* A method in the `JexlScript` class that executes a Jexl script.
*/
class JexlEngineCreateScriptMethod extends Method {
JexlEngineCreateScriptMethod() {
getDeclaringType() instanceof JexlEngine and
hasName("createScript")
}
}
/**
* A method in the JexlScript class that executes a Jexl script.
*/
class JexlScriptExecuteMethod extends Method {
private class JexlScriptExecuteMethod extends Method {
JexlScriptExecuteMethod() {
getDeclaringType() instanceof JexlScript and
hasName("execute")
@@ -254,29 +239,9 @@ class JexlScriptExecuteMethod extends Method {
}
/**
* A method in the JexlScript class that creates a Callable for a Jexl expression.
* A method in the `Callable` class that executes the `Callable`.
*/
class JexlExpressionCallableMethod extends Method {
JexlExpressionCallableMethod() {
getDeclaringType() instanceof JexlExpression and
hasName("callable")
}
}
/**
* A method in the JexlScript class that creates a Callable for a Jexl script.
*/
class JexlScriptCallableMethod extends Method {
JexlScriptCallableMethod() {
getDeclaringType() instanceof JexlScript and
hasName("callable")
}
}
/**
* A method in the Callable class that executes the Callable.
*/
class CallableCallMethod extends Method {
private class CallableCallMethod extends Method {
CallableCallMethod() {
getDeclaringType() instanceof CallableInterface and
hasName("call")
@@ -284,29 +249,9 @@ class CallableCallMethod extends Method {
}
/**
* A method in the JxltEngine class that creates an expression.
* A method in the `JxltEngine.Expression` class that evaluates an expression.
*/
class JxltEngineCreateExpressionMethod extends Method {
JxltEngineCreateExpressionMethod() {
getDeclaringType() instanceof JxltEngine and
hasName("createExpression")
}
}
/**
* A method in the JxltEngine class that creates a template.
*/
class JxltEngineCreateTemplateMethod extends Method {
JxltEngineCreateTemplateMethod() {
getDeclaringType() instanceof JxltEngine and
hasName("createTemplate")
}
}
/**
* A method in the JxltEngine.Expression class that evaluates an expression.
*/
class JxltEngineExpressionEvaluateMethod extends Method {
private class JxltEngineExpressionEvaluateMethod extends Method {
JxltEngineExpressionEvaluateMethod() {
getDeclaringType() instanceof JxltEngineExpression and
hasName("evaluate")
@@ -314,9 +259,9 @@ class JxltEngineExpressionEvaluateMethod extends Method {
}
/**
* A method in the JxltEngine.Expression class that evaluates the immediate sub-expressions.
* A method in the `JxltEngine.Expression` class that evaluates the immediate sub-expressions.
*/
class JxltEngineExpressionPrepareMethod extends Method {
private class JxltEngineExpressionPrepareMethod extends Method {
JxltEngineExpressionPrepareMethod() {
getDeclaringType() instanceof JxltEngineExpression and
hasName("prepare")
@@ -324,9 +269,9 @@ class JxltEngineExpressionPrepareMethod extends Method {
}
/**
* A method in the JxltEngine.Template class that evaluates a template.
* A method in the `JxltEngine.Template` class that evaluates a template.
*/
class JxltEngineTemplateEvaluateMethod extends Method {
private class JxltEngineTemplateEvaluateMethod extends Method {
JxltEngineTemplateEvaluateMethod() {
getDeclaringType() instanceof JxltEngineTemplate and
hasName("evaluate")
@@ -334,29 +279,9 @@ class JxltEngineTemplateEvaluateMethod extends Method {
}
/**
* A method in the UnifiedJEXL class that creates an expression.
* A method in the `UnifiedJEXL.Expression` class that evaluates a template.
*/
class UnifiedJexlParseMethod extends Method {
UnifiedJexlParseMethod() {
getDeclaringType() instanceof UnifiedJexl and
hasName("parse")
}
}
/**
* A method in the UnifiedJEXL class that creates a template.
*/
class UnifiedJexlCreateTemplateMethod extends Method {
UnifiedJexlCreateTemplateMethod() {
getDeclaringType() instanceof UnifiedJexl and
hasName("createTemplate")
}
}
/**
* A method in the UnifiedJEXL.Expression class that evaluates a template.
*/
class UnifiedJexlExpressionEvaluateMethod extends Method {
private class UnifiedJexlExpressionEvaluateMethod extends Method {
UnifiedJexlExpressionEvaluateMethod() {
getDeclaringType() instanceof UnifiedJexlExpression and
hasName("evaluate")
@@ -364,9 +289,9 @@ class UnifiedJexlExpressionEvaluateMethod extends Method {
}
/**
* A method in the UnifiedJEXL.Expression class that evaluates the immediate sub-expressions.
* A method in the `UnifiedJEXL.Expression` class that evaluates the immediate sub-expressions.
*/
class UnifiedJexlExpressionPrepareMethod extends Method {
private class UnifiedJexlExpressionPrepareMethod extends Method {
UnifiedJexlExpressionPrepareMethod() {
getDeclaringType() instanceof UnifiedJexlExpression and
hasName("prepare")
@@ -374,73 +299,73 @@ class UnifiedJexlExpressionPrepareMethod extends Method {
}
/**
* A method in the UnifiedJEXL.Template class that evaluates a template.
* A method in the `UnifiedJEXL.Template` class that evaluates a template.
*/
class UnifiedJexlTemplateEvaluateMethod extends Method {
private class UnifiedJexlTemplateEvaluateMethod extends Method {
UnifiedJexlTemplateEvaluateMethod() {
getDeclaringType() instanceof UnifiedJexlTemplate and
hasName("evaluate")
}
}
class JexlExpression extends RefType {
private class JexlExpression extends RefType {
JexlExpression() {
hasQualifiedName("org.apache.commons.jexl3", "JexlExpression") or
hasQualifiedName("org.apache.commons.jexl2", "Expression")
}
}
class JexlScript extends RefType {
private class JexlScript extends RefType {
JexlScript() {
hasQualifiedName("org.apache.commons.jexl3", "JexlScript") or
hasQualifiedName("org.apache.commons.jexl2", "Script")
}
}
class JexlEngine extends RefType {
private class JexlEngine extends RefType {
JexlEngine() {
hasQualifiedName("org.apache.commons.jexl3", "JexlEngine") or
hasQualifiedName("org.apache.commons.jexl2", "JexlEngine")
}
}
class JxltEngine extends RefType {
private class JxltEngine extends RefType {
JxltEngine() { hasQualifiedName("org.apache.commons.jexl3", "JxltEngine") }
}
class UnifiedJexl extends RefType {
private class UnifiedJexl extends RefType {
UnifiedJexl() { hasQualifiedName("org.apache.commons.jexl2", "UnifiedJEXL") }
}
class JxltEngineExpression extends NestedType {
private class JxltEngineExpression extends NestedType {
JxltEngineExpression() {
getEnclosingType() instanceof JxltEngine and
hasName("Expression")
}
}
class JxltEngineTemplate extends NestedType {
private class JxltEngineTemplate extends NestedType {
JxltEngineTemplate() {
getEnclosingType() instanceof JxltEngine and
hasName("Template")
}
}
class UnifiedJexlExpression extends NestedType {
private class UnifiedJexlExpression extends NestedType {
UnifiedJexlExpression() {
getEnclosingType() instanceof UnifiedJexl and
hasName("Expression")
}
}
class UnifiedJexlTemplate extends NestedType {
private class UnifiedJexlTemplate extends NestedType {
UnifiedJexlTemplate() {
getEnclosingType() instanceof UnifiedJexl and
hasName("Template")
}
}
class CallableInterface extends RefType {
private class CallableInterface extends RefType {
CallableInterface() {
getSourceDeclaration()
.getASourceSupertype*()
@@ -448,6 +373,6 @@ class CallableInterface extends RefType {
}
}
class Reader extends RefType {
private class Reader extends RefType {
Reader() { hasQualifiedName("java.io", "Reader") }
}