Skip to content

Commit e7cd6c9

Browse files
committed
Optimize the query
1 parent 703fbf1 commit e7cd6c9

File tree

3 files changed

+22
-23
lines changed

3 files changed

+22
-23
lines changed

java/ql/src/experimental/Security/CWE/CWE-094/JythonInjection.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import org.python.util.PythonInterpreter;
2+
13
public class JythonInjection extends HttpServlet {
24
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
35
response.setContentType("text/plain");
@@ -10,7 +12,7 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) t
1012
interpreter.setOut(out);
1113
interpreter.setErr(out);
1214

13-
// BAD: allow arbitrary Jython expression to execute
15+
// BAD: allow execution of arbitrary Python code
1416
interpreter.exec(code);
1517
out.flush();
1618

@@ -32,7 +34,7 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response)
3234

3335
try {
3436
interpreter = new PythonInterpreter();
35-
// BAD: allow arbitrary Jython expression to evaluate
37+
// BAD: allow execution of arbitrary Python code
3638
PyObject py = interpreter.eval(code);
3739

3840
response.getWriter().print(py.toString());

java/ql/src/experimental/Security/CWE/CWE-094/JythonInjection.ql

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import java
1313
import semmle.code.java.dataflow.FlowSources
14+
import semmle.code.java.frameworks.spring.SpringController
1415
import DataFlow::PathGraph
1516

1617
/** The class `org.python.util.PythonInterpreter`. */
@@ -22,12 +23,7 @@ class PythonInterpreter extends RefType {
2223
class InterpretExprMethod extends Method {
2324
InterpretExprMethod() {
2425
this.getDeclaringType().getAnAncestor*() instanceof PythonInterpreter and
25-
(
26-
getName().matches("exec%") or
27-
hasName("eval") or
28-
hasName("compile") or
29-
getName().matches("run%")
30-
)
26+
getName().matches(["exec%", "run%", "eval", "compile"])
3127
}
3228
}
3329

@@ -48,14 +44,14 @@ predicate runCode(MethodAccess ma, Expr sink) {
4844
class LoadClassMethod extends Method {
4945
LoadClassMethod() {
5046
this.getDeclaringType().getAnAncestor*() instanceof BytecodeLoader and
51-
(
52-
hasName("makeClass") or
53-
hasName("makeCode")
54-
)
47+
hasName(["makeClass", "makeCode"])
5548
}
5649
}
5750

58-
/** Holds if a Java class file is loaded. */
51+
/**
52+
* Holds if `ma` is a call to a class-loading method, and `sink` is the byte array
53+
* representing the class to be loaded.
54+
*/
5955
predicate loadClass(MethodAccess ma, Expr sink) {
6056
exists(Method m, int i | m = ma.getMethod() |
6157
m instanceof LoadClassMethod and
@@ -69,7 +65,7 @@ class Py extends RefType {
6965
Py() { this.hasQualifiedName("org.python.core", "Py") }
7066
}
7167

72-
/** A method that compiles code with `Py`. */
68+
/** A method declared on class `Py` or one of its descendants that compiles Python code. */
7369
class PyCompileMethod extends Method {
7470
PyCompileMethod() {
7571
this.getDeclaringType().getAnAncestor*() instanceof Py and
@@ -85,7 +81,7 @@ predicate compile(MethodAccess ma, Expr sink) {
8581
)
8682
}
8783

88-
/** Sink of an expression loaded by Jython. */
84+
/** An expression loaded by Jython. */
8985
class CodeInjectionSink extends DataFlow::ExprNode {
9086
CodeInjectionSink() {
9187
runCode(_, this.getExpr()) or
@@ -103,17 +99,18 @@ class CodeInjectionSink extends DataFlow::ExprNode {
10399
class CodeInjectionConfiguration extends TaintTracking::Configuration {
104100
CodeInjectionConfiguration() { this = "CodeInjectionConfiguration" }
105101

106-
override predicate isSource(DataFlow::Node source) {
107-
source instanceof RemoteFlowSource
108-
or
109-
source instanceof LocalUserInput
110-
}
102+
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
111103

112104
override predicate isSink(DataFlow::Node sink) { sink instanceof CodeInjectionSink }
113105

114106
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
115107
// @RequestBody MyQueryObj query; interpreter.exec(query.getInterpreterCode());
116-
exists(MethodAccess ma | ma.getQualifier() = node1.asExpr() and ma = node2.asExpr())
108+
exists(MethodAccess ma |
109+
ma.getMethod().getDeclaringType().getASubtype*() instanceof SpringUntrustedDataType and
110+
not ma.getMethod().getDeclaringType() instanceof TypeObject and
111+
ma.getQualifier() = node1.asExpr() and
112+
ma = node2.asExpr()
113+
)
117114
}
118115
}
119116

java/ql/test/experimental/query-tests/security/CWE-094/JythonInjection.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public JythonInjection() {
2222
super();
2323
}
2424

25-
// BAD: allow arbitrary Jython expression to execute
25+
// BAD: allow execution of arbitrary Python code
2626
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
2727
response.setContentType("text/plain");
2828
String code = request.getParameter("code");
@@ -47,7 +47,7 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) t
4747
}
4848
}
4949

50-
// BAD: allow arbitrary Jython expression to evaluate
50+
// BAD: allow execution of arbitrary Python code
5151
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
5252
response.setContentType("text/plain");
5353
String code = request.getParameter("code");

0 commit comments

Comments
 (0)