mirror of
https://github.com/github/codeql.git
synced 2026-05-05 21:55:19 +02:00
Refactor to CSV sink model
This commit is contained in:
@@ -12,10 +12,28 @@
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import DataFlow
|
||||
import DataFlow::PathGraph
|
||||
import OgnlInjectionLib
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for unvalidated user input that is used in OGNL EL evaluation.
|
||||
*/
|
||||
class OgnlInjectionFlowConfig extends TaintTracking::Configuration {
|
||||
OgnlInjectionFlowConfig() { this = "OgnlInjectionFlowConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof OgnlInjectionSink }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
any(OgnlInjectionAdditionalTaintStep c).step(node1, node2)
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, OgnlInjectionFlowConfig conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "OGNL expression might include input from $@.",
|
||||
|
||||
@@ -1,101 +1,59 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import DataFlow
|
||||
import DataFlow::PathGraph
|
||||
import semmle.code.java.dataflow.ExternalFlow
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for unvalidated user input that is used in OGNL EL evaluation.
|
||||
* A data flow sink for unvalidated user input that is used in OGNL EL evaluation.
|
||||
*
|
||||
* Extend this class to add your own OGNL injection sinks.
|
||||
*/
|
||||
class OgnlInjectionFlowConfig extends TaintTracking::Configuration {
|
||||
OgnlInjectionFlowConfig() { this = "OgnlInjectionFlowConfig" }
|
||||
abstract class OgnlInjectionSink extends DataFlow::Node { }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
/**
|
||||
* A unit class for adding additional taint steps.
|
||||
*
|
||||
* Extend this class to add additional taint steps that should apply to the `OgnlInjectionFlowConfig`.
|
||||
*/
|
||||
class OgnlInjectionAdditionalTaintStep extends Unit {
|
||||
abstract predicate step(DataFlow::Node node1, DataFlow::Node node2);
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof OgnlInjectionSink }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType
|
||||
private class DefaultOgnlInjectionSinkModel extends SinkModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
"org.apache.commons.ognl;Ognl;false;getValue;;;Argument[-1..0];ognl-injection",
|
||||
"org.apache.commons.ognl;Ognl;false;setValue;;;Argument[-1..0];ognl-injection",
|
||||
"ognl;Ognl;false;getValue;;;Argument[-1..0];ognl-injection",
|
||||
"ognl;Ognl;false;setValue;;;Argument[-1..0];ognl-injection",
|
||||
"org.apache.commons.ognl;Node;false;getValue;;;Argument[-1..0];ognl-injection",
|
||||
"org.apache.commons.ognl;Node;false;setValue;;;Argument[-1..0];ognl-injection",
|
||||
"ognl;Node;false;getValue;;;Argument[-1..0];ognl-injection",
|
||||
"ognl;Node;false;setValue;;;Argument[-1..0];ognl-injection",
|
||||
"com.opensymphony.xwork2.ognl;OgnlUtil;false;getValue;;;Argument[-1..0];ognl-injection",
|
||||
"com.opensymphony.xwork2.ognl;OgnlUtil;false;setValue;;;Argument[-1..0];ognl-injection",
|
||||
"com.opensymphony.xwork2.ognl;OgnlUtil;false;callMethod;;;Argument[-1..0];ognl-injection"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
parseCompileExpressionStep(node1, node2)
|
||||
}
|
||||
private class DefaultOgnlInjectionSink extends OgnlInjectionSink {
|
||||
DefaultOgnlInjectionSink() { sinkNode(this, "ognl-injection") }
|
||||
}
|
||||
|
||||
/** The class `org.apache.commons.ognl.Ognl` or `ognl.Ognl`. */
|
||||
class TypeOgnl extends Class {
|
||||
private class TypeOgnl extends Class {
|
||||
TypeOgnl() {
|
||||
this.hasQualifiedName("org.apache.commons.ognl", "Ognl") or
|
||||
this.hasQualifiedName("ognl", "Ognl")
|
||||
}
|
||||
}
|
||||
|
||||
/** The interface `org.apache.commons.ognl.Node` or `ognl.Node`. */
|
||||
class TypeNode extends Interface {
|
||||
TypeNode() {
|
||||
this.hasQualifiedName("org.apache.commons.ognl", "Node") or
|
||||
this.hasQualifiedName("ognl", "Node")
|
||||
}
|
||||
}
|
||||
|
||||
/** The class `com.opensymphony.xwork2.ognl.OgnlUtil`. */
|
||||
class TypeOgnlUtil extends Class {
|
||||
TypeOgnlUtil() { this.hasQualifiedName("com.opensymphony.xwork2.ognl", "OgnlUtil") }
|
||||
}
|
||||
|
||||
/**
|
||||
* OGNL sink for OGNL injection vulnerabilities, i.e. 1st argument to `getValue` or `setValue`
|
||||
* method from `Ognl` or `getValue` or `setValue` method from `Node`.
|
||||
*/
|
||||
predicate ognlSinkMethod(Method m, int index) {
|
||||
(
|
||||
m.getDeclaringType() instanceof TypeOgnl
|
||||
or
|
||||
m.getDeclaringType().getAnAncestor*() instanceof TypeNode
|
||||
) and
|
||||
(
|
||||
m.hasName("getValue") or
|
||||
m.hasName("setValue")
|
||||
) and
|
||||
index = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Struts sink for OGNL injection vulnerabilities, i.e. 1st argument to `getValue`, `setValue` or
|
||||
* `callMethod` method from `OgnlUtil`.
|
||||
*/
|
||||
predicate strutsSinkMethod(Method m, int index) {
|
||||
m.getDeclaringType() instanceof TypeOgnlUtil and
|
||||
(
|
||||
m.hasName("getValue") or
|
||||
m.hasName("setValue") or
|
||||
m.hasName("callMethod")
|
||||
) and
|
||||
index = 0
|
||||
}
|
||||
|
||||
/** Holds if parameter at index `index` in method `m` is OGNL injection sink. */
|
||||
predicate ognlInjectionSinkMethod(Method m, int index) {
|
||||
ognlSinkMethod(m, index) or
|
||||
strutsSinkMethod(m, index)
|
||||
}
|
||||
|
||||
/** A data flow sink for unvalidated user input that is used in OGNL EL evaluation. */
|
||||
class OgnlInjectionSink extends DataFlow::ExprNode {
|
||||
OgnlInjectionSink() {
|
||||
exists(MethodAccess ma, Method m, int index |
|
||||
ma.getMethod() = m and
|
||||
(ma.getArgument(index) = this.getExpr() or ma.getQualifier() = this.getExpr()) and
|
||||
ognlInjectionSinkMethod(m, index)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n1` to `n2` is a dataflow step that converts between `String` and `Object` or `Node`,
|
||||
* i.e. `Ognl.parseExpression(tainted)` or `Ognl.compileExpression(tainted)`.
|
||||
*/
|
||||
predicate parseCompileExpressionStep(ExprNode n1, ExprNode n2) {
|
||||
private predicate parseCompileExpressionStep(DataFlow::Node n1, DataFlow::Node n2) {
|
||||
exists(MethodAccess ma, Method m, int index |
|
||||
n1.asExpr() = ma.getArgument(index) and
|
||||
n2.asExpr() = ma and
|
||||
@@ -107,3 +65,9 @@ predicate parseCompileExpressionStep(ExprNode n1, ExprNode n2) {
|
||||
m.hasName("compileExpression") and index = 2
|
||||
)
|
||||
}
|
||||
|
||||
private class DefaultOgnlInjectionAdditionalTaintStep extends OgnlInjectionAdditionalTaintStep {
|
||||
override predicate step(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
parseCompileExpressionStep(node1, node2)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user