Skip to content

Commit a6a0fa2

Browse files
committed
*)add XQExpression.executeQuery(0) sink
1 parent 97690b4 commit a6a0fa2

File tree

8 files changed

+202
-29
lines changed

8 files changed

+202
-29
lines changed

java/ql/src/Security/CWE/CWE-652/XQueryInjection.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,18 @@ public void bad(HttpServletRequest request) throws XQException {
2020
}
2121
}
2222

23+
public void bad1(HttpServletRequest request) throws XQException {
24+
String name = request.getParameter("name");
25+
XQDataSource xqds = new SaxonXQDataSource();
26+
String query = "for $user in doc(\"users.xml\")/Users/User[name='" + name + "'] return $user/password";
27+
XQConnection conn = xqds.getConnection();
28+
XQExpression expr = conn.createExpression();
29+
XQResultSequence result = expr.executeQuery(query);
30+
while (result.next()){
31+
System.out.println(result.getItemAsString(null));
32+
}
33+
}
34+
2335
public void good(HttpServletRequest request) throws XQException {
2436
String name = request.getParameter("name");
2537
XQDataSource ds = new SaxonXQDataSource();
@@ -32,4 +44,18 @@ public void good(HttpServletRequest request) throws XQException {
3244
while (result.next()){
3345
System.out.println(result.getItemAsString(null));
3446
}
47+
}
48+
49+
public void good1(HttpServletRequest request) throws XQException {
50+
String name = request.getParameter("name");
51+
String query = "declare variable $name as xs:string external;"
52+
+ " for $user in doc(\"users.xml\")/Users/User[name=$name] return $user/password";
53+
XQDataSource xqds = new SaxonXQDataSource();
54+
XQConnection conn = xqds.getConnection();
55+
XQExpression expr = conn.createExpression();
56+
expr.bindString(new QName("name"), name, conn.createAtomicType(XQItemType.XQBASETYPE_STRING));
57+
XQResultSequence result = expr.executeQuery(query);
58+
while (result.next()){
59+
System.out.println(result.getItemAsString(null));
60+
}
3561
}

java/ql/src/Security/CWE/CWE-652/XQueryInjection.ql

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,15 @@ class XQueryInjectionConfig extends TaintTracking::Configuration {
2424
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
2525

2626
override predicate isSink(DataFlow::Node sink) {
27-
sink.asExpr() = any(XQueryExecuteCall execute).getPreparedExpression()
27+
sink.asExpr() = any(XQueryPreparedExecuteCall xpec).getPreparedExpression() or
28+
sink.asExpr() = any(XQueryExecuteCall xec).getExecuteQueryArgument()
2829
}
2930

3031
/**
3132
* Conveys taint from the input to a `prepareExpression` call to the returned prepared expression.
3233
*/
3334
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
34-
exists(XQueryParserCall parser |
35-
pred.asExpr() = parser.getInput() and succ.asExpr() = parser)
35+
exists(XQueryParserCall parser | pred.asExpr() = parser.getInput() and succ.asExpr() = parser)
3636
}
3737
}
3838

java/ql/src/Security/CWE/CWE-652/XQueryInjectionLib.qll

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,33 @@ class XQueryParserCall extends MethodAccess {
2020
}
2121

2222
/** A call to `XQPreparedExpression.executeQuery`. */
23-
class XQueryExecuteCall extends MethodAccess {
24-
XQueryExecuteCall() {
25-
exists(Method m | this.getMethod() = m and
26-
m.hasName("executeQuery") and
27-
m.getDeclaringType()
28-
.getASourceSupertype*()
29-
.hasQualifiedName("javax.xml.xquery", "XQPreparedExpression")
23+
class XQueryPreparedExecuteCall extends MethodAccess {
24+
XQueryPreparedExecuteCall() {
25+
exists(Method m |
26+
this.getMethod() = m and
27+
m.hasName("executeQuery") and
28+
m.getDeclaringType()
29+
.getASourceSupertype*()
30+
.hasQualifiedName("javax.xml.xquery", "XQPreparedExpression")
3031
)
3132
}
3233

3334
/** Return this prepared expression. */
3435
Expr getPreparedExpression() { result = this.getQualifier() }
3536
}
37+
38+
/** A call to `XQExpression.executeQuery`. */
39+
class XQueryExecuteCall extends MethodAccess {
40+
XQueryExecuteCall() {
41+
exists(Method m |
42+
this.getMethod() = m and
43+
m.hasName("executeQuery") and
44+
m.getDeclaringType()
45+
.getASourceSupertype*()
46+
.hasQualifiedName("javax.xml.xquery", "XQExpression")
47+
)
48+
}
49+
50+
/** Return this execute query argument. */
51+
Expr getExecuteQueryArgument() { result = this.getArgument(0) }
52+
}
Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,35 @@
11
edges
2-
| XQueryInjection.java:26:37:26:65 | prepareExpression(...) : XQPreparedExpression | XQueryInjection.java:27:35:27:38 | xqpe |
3-
| XQueryInjection.java:41:37:41:65 | prepareExpression(...) : XQPreparedExpression | XQueryInjection.java:42:35:42:38 | xqpe |
4-
| XQueryInjection.java:53:37:53:64 | prepareExpression(...) : XQPreparedExpression | XQueryInjection.java:54:35:54:38 | xqpe |
5-
| XQueryInjection.java:66:37:66:62 | prepareExpression(...) : XQPreparedExpression | XQueryInjection.java:67:35:67:38 | xqpe |
2+
| XQueryInjection.java:42:23:42:50 | getParameter(...) : String | XQueryInjection.java:47:35:47:38 | xqpe |
3+
| XQueryInjection.java:55:23:55:50 | getParameter(...) : String | XQueryInjection.java:60:53:60:57 | query |
4+
| XQueryInjection.java:68:32:68:59 | nameStr : String | XQueryInjection.java:73:35:73:38 | xqpe |
5+
| XQueryInjection.java:80:33:80:60 | nameStr : String | XQueryInjection.java:85:53:85:57 | query |
6+
| XQueryInjection.java:93:28:93:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:97:35:97:38 | xqpe |
7+
| XQueryInjection.java:105:28:105:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:109:53:109:56 | name |
8+
| XQueryInjection.java:117:28:117:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:122:35:122:38 | xqpe |
9+
| XQueryInjection.java:130:28:130:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:135:53:135:54 | br |
610
nodes
7-
| XQueryInjection.java:26:37:26:65 | prepareExpression(...) : XQPreparedExpression | semmle.label | prepareExpression(...) : XQPreparedExpression |
8-
| XQueryInjection.java:27:35:27:38 | xqpe | semmle.label | xqpe |
9-
| XQueryInjection.java:41:37:41:65 | prepareExpression(...) : XQPreparedExpression | semmle.label | prepareExpression(...) : XQPreparedExpression |
10-
| XQueryInjection.java:42:35:42:38 | xqpe | semmle.label | xqpe |
11-
| XQueryInjection.java:53:37:53:64 | prepareExpression(...) : XQPreparedExpression | semmle.label | prepareExpression(...) : XQPreparedExpression |
12-
| XQueryInjection.java:54:35:54:38 | xqpe | semmle.label | xqpe |
13-
| XQueryInjection.java:66:37:66:62 | prepareExpression(...) : XQPreparedExpression | semmle.label | prepareExpression(...) : XQPreparedExpression |
14-
| XQueryInjection.java:67:35:67:38 | xqpe | semmle.label | xqpe |
11+
| XQueryInjection.java:42:23:42:50 | getParameter(...) : String | semmle.label | getParameter(...) : String |
12+
| XQueryInjection.java:47:35:47:38 | xqpe | semmle.label | xqpe |
13+
| XQueryInjection.java:55:23:55:50 | getParameter(...) : String | semmle.label | getParameter(...) : String |
14+
| XQueryInjection.java:60:53:60:57 | query | semmle.label | query |
15+
| XQueryInjection.java:68:32:68:59 | nameStr : String | semmle.label | nameStr : String |
16+
| XQueryInjection.java:73:35:73:38 | xqpe | semmle.label | xqpe |
17+
| XQueryInjection.java:80:33:80:60 | nameStr : String | semmle.label | nameStr : String |
18+
| XQueryInjection.java:85:53:85:57 | query | semmle.label | query |
19+
| XQueryInjection.java:93:28:93:51 | getInputStream(...) : ServletInputStream | semmle.label | getInputStream(...) : ServletInputStream |
20+
| XQueryInjection.java:97:35:97:38 | xqpe | semmle.label | xqpe |
21+
| XQueryInjection.java:105:28:105:51 | getInputStream(...) : ServletInputStream | semmle.label | getInputStream(...) : ServletInputStream |
22+
| XQueryInjection.java:109:53:109:56 | name | semmle.label | name |
23+
| XQueryInjection.java:117:28:117:51 | getInputStream(...) : ServletInputStream | semmle.label | getInputStream(...) : ServletInputStream |
24+
| XQueryInjection.java:122:35:122:38 | xqpe | semmle.label | xqpe |
25+
| XQueryInjection.java:130:28:130:51 | getInputStream(...) : ServletInputStream | semmle.label | getInputStream(...) : ServletInputStream |
26+
| XQueryInjection.java:135:53:135:54 | br | semmle.label | br |
1527
#select
16-
| XQueryInjection.java:27:35:27:38 | xqpe | XQueryInjection.java:26:37:26:65 | prepareExpression(...) : XQPreparedExpression | XQueryInjection.java:27:35:27:38 | xqpe | XQuery query might include code from $@. | XQueryInjection.java:26:37:26:65 | prepareExpression(...) | this user input |
17-
| XQueryInjection.java:42:35:42:38 | xqpe | XQueryInjection.java:41:37:41:65 | prepareExpression(...) : XQPreparedExpression | XQueryInjection.java:42:35:42:38 | xqpe | XQuery query might include code from $@. | XQueryInjection.java:41:37:41:65 | prepareExpression(...) | this user input |
18-
| XQueryInjection.java:54:35:54:38 | xqpe | XQueryInjection.java:53:37:53:64 | prepareExpression(...) : XQPreparedExpression | XQueryInjection.java:54:35:54:38 | xqpe | XQuery query might include code from $@. | XQueryInjection.java:53:37:53:64 | prepareExpression(...) | this user input |
19-
| XQueryInjection.java:67:35:67:38 | xqpe | XQueryInjection.java:66:37:66:62 | prepareExpression(...) : XQPreparedExpression | XQueryInjection.java:67:35:67:38 | xqpe | XQuery query might include code from $@. | XQueryInjection.java:66:37:66:62 | prepareExpression(...) | this user input |
28+
| XQueryInjection.java:47:35:47:38 | xqpe | XQueryInjection.java:42:23:42:50 | getParameter(...) : String | XQueryInjection.java:47:35:47:38 | xqpe | XQuery query might include code from $@. | XQueryInjection.java:42:23:42:50 | getParameter(...) | this user input |
29+
| XQueryInjection.java:60:53:60:57 | query | XQueryInjection.java:55:23:55:50 | getParameter(...) : String | XQueryInjection.java:60:53:60:57 | query | XQuery query might include code from $@. | XQueryInjection.java:55:23:55:50 | getParameter(...) | this user input |
30+
| XQueryInjection.java:73:35:73:38 | xqpe | XQueryInjection.java:68:32:68:59 | nameStr : String | XQueryInjection.java:73:35:73:38 | xqpe | XQuery query might include code from $@. | XQueryInjection.java:68:32:68:59 | nameStr | this user input |
31+
| XQueryInjection.java:85:53:85:57 | query | XQueryInjection.java:80:33:80:60 | nameStr : String | XQueryInjection.java:85:53:85:57 | query | XQuery query might include code from $@. | XQueryInjection.java:80:33:80:60 | nameStr | this user input |
32+
| XQueryInjection.java:97:35:97:38 | xqpe | XQueryInjection.java:93:28:93:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:97:35:97:38 | xqpe | XQuery query might include code from $@. | XQueryInjection.java:93:28:93:51 | getInputStream(...) | this user input |
33+
| XQueryInjection.java:109:53:109:56 | name | XQueryInjection.java:105:28:105:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:109:53:109:56 | name | XQuery query might include code from $@. | XQueryInjection.java:105:28:105:51 | getInputStream(...) | this user input |
34+
| XQueryInjection.java:122:35:122:38 | xqpe | XQueryInjection.java:117:28:117:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:122:35:122:38 | xqpe | XQuery query might include code from $@. | XQueryInjection.java:117:28:117:51 | getInputStream(...) | this user input |
35+
| XQueryInjection.java:135:53:135:54 | br | XQueryInjection.java:130:28:130:51 | getInputStream(...) : ServletInputStream | XQueryInjection.java:135:53:135:54 | br | XQuery query might include code from $@. | XQueryInjection.java:130:28:130:51 | getInputStream(...) | this user input |

java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.java

Lines changed: 86 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import javax.xml.xquery.XQConnection;
77
import javax.xml.xquery.XQDataSource;
88
import javax.xml.xquery.XQException;
9+
import javax.xml.xquery.XQExpression;
910
import javax.xml.xquery.XQItemType;
1011
import javax.xml.xquery.XQPreparedExpression;
1112
import javax.xml.xquery.XQResultSequence;
@@ -17,6 +18,25 @@
1718
@Controller
1819
public class XQueryInjection {
1920

21+
public static void main(String[] args) throws Exception {
22+
XQDataSource xqds = new SaxonXQDataSource();
23+
XQConnection conn;
24+
try {
25+
String name = "admin";
26+
String query = "declare variable $name as xs:string external;"
27+
+ " for $user in doc(\"users.xml\")/Users/User[name=$name] return $user/password";
28+
conn = xqds.getConnection();
29+
XQExpression expr = conn.createExpression();
30+
expr.bindString(new QName("name"), name, conn.createAtomicType(XQItemType.XQBASETYPE_STRING));
31+
XQResultSequence result = expr.executeQuery(query);
32+
while (result.next()){
33+
System.out.println(result.getItemAsString(null));
34+
}
35+
} catch (XQException e) {
36+
e.printStackTrace();
37+
}
38+
}
39+
2040
@RequestMapping
2141
public void testRequestbad(HttpServletRequest request) throws Exception {
2242
String name = request.getParameter("name");
@@ -28,23 +48,46 @@ public void testRequestbad(HttpServletRequest request) throws Exception {
2848
while (result.next()){
2949
System.out.println(result.getItemAsString(null));
3050
}
51+
}
3152

53+
@RequestMapping
54+
public void testRequestbad1(HttpServletRequest request) throws Exception {
55+
String name = request.getParameter("name");
56+
XQDataSource xqds = new SaxonXQDataSource();
57+
String query = "for $user in doc(\"users.xml\")/Users/User[name='" + name + "'] return $user/password";
58+
XQConnection conn = xqds.getConnection();
59+
XQExpression expr = conn.createExpression();
60+
XQResultSequence result = expr.executeQuery(query);
61+
while (result.next()){
62+
System.out.println(result.getItemAsString(null));
63+
}
3264
}
3365

3466

3567
@RequestMapping
3668
public void testStringtbad(@RequestParam String nameStr) throws XQException {
37-
String name = nameStr;
3869
XQDataSource ds = new SaxonXQDataSource();
3970
XQConnection conn = ds.getConnection();
40-
String query = "for $user in doc(\"users.xml\")/Users/User[name='" + name + "'] return $user/password";
71+
String query = "for $user in doc(\"users.xml\")/Users/User[name='" + nameStr + "'] return $user/password";
4172
XQPreparedExpression xqpe = conn.prepareExpression(query);
4273
XQResultSequence result = xqpe.executeQuery();
4374
while (result.next()){
4475
System.out.println(result.getItemAsString(null));
4576
}
4677
}
4778

79+
@RequestMapping
80+
public void testStringtbad1(@RequestParam String nameStr) throws XQException {
81+
XQDataSource xqds = new SaxonXQDataSource();
82+
String query = "for $user in doc(\"users.xml\")/Users/User[name='" + nameStr + "'] return $user/password";
83+
XQConnection conn = xqds.getConnection();
84+
XQExpression expr = conn.createExpression();
85+
XQResultSequence result = expr.executeQuery(query);
86+
while (result.next()){
87+
System.out.println(result.getItemAsString(null));
88+
}
89+
}
90+
4891
@RequestMapping
4992
public void testInputStreambad(HttpServletRequest request) throws Exception {
5093
InputStream name = request.getInputStream();
@@ -57,6 +100,18 @@ public void testInputStreambad(HttpServletRequest request) throws Exception {
57100
}
58101
}
59102

103+
@RequestMapping
104+
public void testInputStreambad1(HttpServletRequest request) throws Exception {
105+
InputStream name = request.getInputStream();
106+
XQDataSource xqds = new SaxonXQDataSource();
107+
XQConnection conn = xqds.getConnection();
108+
XQExpression expr = conn.createExpression();
109+
XQResultSequence result = expr.executeQuery(name);
110+
while (result.next()){
111+
System.out.println(result.getItemAsString(null));
112+
}
113+
}
114+
60115
@RequestMapping
61116
public void testReaderbad(HttpServletRequest request) throws Exception {
62117
InputStream name = request.getInputStream();
@@ -70,6 +125,19 @@ public void testReaderbad(HttpServletRequest request) throws Exception {
70125
}
71126
}
72127

128+
@RequestMapping
129+
public void testReaderbad1(HttpServletRequest request) throws Exception {
130+
InputStream name = request.getInputStream();
131+
BufferedReader br = new BufferedReader(new InputStreamReader(name));
132+
XQDataSource xqds = new SaxonXQDataSource();
133+
XQConnection conn = xqds.getConnection();
134+
XQExpression expr = conn.createExpression();
135+
XQResultSequence result = expr.executeQuery(br);
136+
while (result.next()){
137+
System.out.println(result.getItemAsString(null));
138+
}
139+
}
140+
73141
@RequestMapping
74142
public void good(HttpServletRequest request) throws XQException {
75143
String name = request.getParameter("name");
@@ -84,4 +152,19 @@ public void good(HttpServletRequest request) throws XQException {
84152
System.out.println(result.getItemAsString(null));
85153
}
86154
}
87-
}
155+
156+
@RequestMapping
157+
public void good1(HttpServletRequest request) throws XQException {
158+
String name = request.getParameter("name");
159+
String query = "declare variable $name as xs:string external;"
160+
+ " for $user in doc(\"users.xml\")/Users/User[name=$name] return $user/password";
161+
XQDataSource xqds = new SaxonXQDataSource();
162+
XQConnection conn = xqds.getConnection();
163+
XQExpression expr = conn.createExpression();
164+
expr.bindString(new QName("name"), name, conn.createAtomicType(XQItemType.XQBASETYPE_STRING));
165+
XQResultSequence result = expr.executeQuery(query);
166+
while (result.next()){
167+
System.out.println(result.getItemAsString(null));
168+
}
169+
}
170+
}

java/ql/test/stubs/saxon-xqj-9.x/javax/xml/xquery/XQConnection.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import java.io.Reader;
55

66
public interface XQConnection extends XQDataFactory {
7+
8+
XQExpression createExpression() throws XQException;
79

810
XQPreparedExpression prepareExpression(String var1) throws XQException;
911

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package javax.xml.xquery;
2+
3+
import java.io.InputStream;
4+
import java.io.Reader;
5+
6+
public interface XQExpression extends XQDynamicContext {
7+
8+
void cancel() throws XQException;
9+
10+
boolean isClosed();
11+
12+
void close() throws XQException;
13+
14+
void executeCommand(String var1) throws XQException;
15+
16+
void executeCommand(Reader var1) throws XQException;
17+
18+
XQResultSequence executeQuery(String var1) throws XQException;
19+
20+
XQResultSequence executeQuery(Reader var1) throws XQException;
21+
22+
XQResultSequence executeQuery(InputStream var1) throws XQException;
23+
24+
XQStaticContext getStaticContext() throws XQException;
25+
}

java/ql/test/stubs/saxon-xqj-9.x/net/sf/saxon/xqj/SaxonXQConnection.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ public class SaxonXQConnection extends SaxonXQDataFactory implements XQConnecti
1515
SaxonXQConnection(SaxonXQDataSource dataSource) {
1616
}
1717

18+
public XQExpression createExpression() throws XQException {
19+
return null;
20+
}
21+
1822
public XQPreparedExpression prepareExpression(InputStream xquery) throws XQException {
1923
return null;
2024
}

0 commit comments

Comments
 (0)