|
1 | 1 | import java |
2 | 2 | import semmle.code.java.dataflow.FlowSources |
| 3 | +import semmle.code.java.dataflow.TaintTracking2 |
| 4 | +import DataFlow::PathGraph |
3 | 5 |
|
4 | | -class XQueryInjectionConfig extends TaintTracking::Configuration { |
5 | | - XQueryInjectionConfig() { this = "XQueryInjectionConfig" } |
| 6 | +/** A call to `XQConnection.prepareExpression`. */ |
| 7 | +class XQueryParserCall extends MethodAccess { |
| 8 | + XQueryParserCall() { |
| 9 | + exists(Method m | |
| 10 | + this.getMethod() = m and |
| 11 | + m.getDeclaringType() |
| 12 | + .getASourceSupertype*() |
| 13 | + .hasQualifiedName("javax.xml.xquery", "XQConnection") and |
| 14 | + m.hasName("prepareExpression") |
| 15 | + ) |
| 16 | + } |
| 17 | + // return the first parameter of the `bindString` method and use it as a sink |
| 18 | + Expr getSink() { result = this.getArgument(0) } |
| 19 | +} |
| 20 | + |
| 21 | +/** A call to `XQDynamicContext.bindString`. */ |
| 22 | +class XQueryBindStringCall extends MethodAccess { |
| 23 | + XQueryBindStringCall() { |
| 24 | + exists(Method m | |
| 25 | + this.getMethod() = m and |
| 26 | + m.getDeclaringType() |
| 27 | + .getASourceSupertype*() |
| 28 | + .hasQualifiedName("javax.xml.xquery", "XQDynamicContext") and |
| 29 | + m.hasName("bindString") |
| 30 | + ) |
| 31 | + } |
| 32 | + // return the second parameter of the `bindString` method and use it as a sink |
| 33 | + Expr getSink() { result = this.getArgument(1) } |
| 34 | +} |
| 35 | + |
| 36 | +/** Used to determine whether to call the `prepareExpression` method, and the first parameter value can be remotely controlled. */ |
| 37 | +class ParserParameterRemoteFlowConf extends TaintTracking2::Configuration { |
| 38 | + ParserParameterRemoteFlowConf() { this = "ParserParameterRemoteFlowConf" } |
6 | 39 |
|
7 | | - override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } |
| 40 | + override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource } |
8 | 41 |
|
9 | | - override predicate isSink(DataFlow::Node sink) { sink instanceof XQueryInjectionSink } |
| 42 | + override predicate isSink(DataFlow::Node sink) { |
| 43 | + exists(XQueryParserCall xqpc | xqpc.getSink() = sink.asExpr()) |
| 44 | + } |
10 | 45 | } |
11 | 46 |
|
12 | | -/*Find if the executeQuery method is finally called.*/ |
13 | | -predicate executeQuery(MethodAccess ma) { |
14 | | - exists(LocalVariableDeclExpr lvd, MethodAccess ma1, Method m | lvd.getAChildExpr() = ma | |
15 | | - m = ma1.getMethod() and |
16 | | - m.hasName("executeQuery") and |
17 | | - m.getDeclaringType() |
18 | | - .getASourceSupertype*() |
19 | | - .hasQualifiedName("javax.xml.xquery", "XQPreparedExpression") and |
20 | | - ma1.getQualifier() = lvd.getAnAccess() |
21 | | - ) |
| 47 | +/** Used to determine whether to call the `bindString` method, and the second parameter value can be controlled remotely. */ |
| 48 | +class BindParameterRemoteFlowConf extends TaintTracking2::Configuration { |
| 49 | + BindParameterRemoteFlowConf() { this = "BindParameterRemoteFlowConf" } |
| 50 | + |
| 51 | + override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource } |
| 52 | + |
| 53 | + override predicate isSink(DataFlow::Node sink) { |
| 54 | + exists(XQueryBindStringCall xqbsc | xqbsc.getSink() = sink.asExpr()) |
| 55 | + } |
22 | 56 | } |
23 | 57 |
|
24 | | -class XQueryInjectionSink extends DataFlow::ExprNode { |
25 | | - XQueryInjectionSink() { |
26 | | - exists(MethodAccess ma, Method m | m = ma.getMethod() | |
| 58 | +/** |
| 59 | + * A data flow source for XQuery injection vulnerability. |
| 60 | + * 1. `prepareExpression` call as sink. |
| 61 | + * 2. Determine whether the `var1` parameter of `prepareExpression` method can be controlled remotely. |
| 62 | + */ |
| 63 | +class XQueryInjectionSource extends DataFlow::ExprNode { |
| 64 | + XQueryInjectionSource() { |
| 65 | + exists(MethodAccess ma, Method m, ParserParameterRemoteFlowConf conf, DataFlow::Node node | |
| 66 | + m = ma.getMethod() |
| 67 | + | |
27 | 68 | m.hasName("prepareExpression") and |
28 | 69 | m.getDeclaringType() |
29 | 70 | .getASourceSupertype*() |
30 | 71 | .hasQualifiedName("javax.xml.xquery", "XQConnection") and |
31 | | - executeQuery(ma) and |
32 | | - asExpr() = ma.getArgument(0) |
| 72 | + asExpr() = ma and |
| 73 | + node.asExpr() = ma.getArgument(0) and |
| 74 | + conf.hasFlowTo(node) |
| 75 | + ) |
| 76 | + } |
| 77 | +} |
| 78 | + |
| 79 | +/** A data flow sink for XQuery injection vulnerability. */ |
| 80 | +class XQueryInjectionSink extends DataFlow::Node { |
| 81 | + XQueryInjectionSink() { |
| 82 | + exists(MethodAccess ma, Method m | m = ma.getMethod() | |
| 83 | + m.hasName("executeQuery") and |
| 84 | + m.getDeclaringType() |
| 85 | + .getASourceSupertype*() |
| 86 | + .hasQualifiedName("javax.xml.xquery", "XQPreparedExpression") and |
| 87 | + asExpr() = ma.getQualifier() |
33 | 88 | ) |
34 | 89 | } |
35 | 90 | } |
0 commit comments