Merge pull request #5467 from p0wn4j/groovy-execute

[Java] CWE-094: Query to detect Groovy Code Injections
This commit is contained in:
Chris Smowton
2021-04-20 14:49:56 +01:00
committed by GitHub
17 changed files with 729 additions and 1 deletions

View File

@@ -0,0 +1,81 @@
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
<qhelp>
<overview>
<p>
Apache Groovy is a powerful, optionally typed and dynamic language,
with static-typing and static compilation capabilities.
It integrates smoothly with any Java program,
and immediately delivers to your application powerful features,
including scripting capabilities, Domain-Specific Language authoring,
runtime and compile-time meta-programming and functional programming.
If a Groovy script is built using attacker-controlled data,
and then evaluated, then it may allow the attacker to achieve RCE.
</p>
</overview>
<recommendation>
<p>
It is generally recommended to avoid using untrusted input in a Groovy evaluation.
If this is not possible, use a sandbox solution. Developers must also take care that Groovy
compile-time metaprogramming can also lead to RCE: it is possible to achieve RCE by compiling
a Groovy script (see the article "Abusing Meta Programming for Unauthenticated RCE!" linked below).
Groovy's <code>SecureASTCustomizer</code> allows securing source code by controlling what code constructs are permitted.
This is typically done when using Groovy for its scripting or domain specific language (DSL) features.
The fundamental problem is that Groovy is a dynamic language, yet <code>SecureASTCustomizer</code> works by looking at Groovy AST statically.
This makes it very easy for an attacker to bypass many of the intended checks
(see https://kohsuke.org/2012/04/27/groovy-secureastcustomizer-is-harmful/).
Therefore, besides <code>SecureASTCustomizer</code>, runtime checks are also necessary before calling Groovy methods
(see https://melix.github.io/blog/2015/03/sandboxing.html).
It is also possible to use a block-list method, excluding unwanted classes from being loaded by the JVM.
This method is not always recommended, because block-lists can be bypassed by unexpected values.
</p>
</recommendation>
<example>
<p>
The following example uses untrusted data to evaluate a Groovy script.
</p>
<sample src="GroovyInjectionBad.java" />
<p>
The following example uses classloader block-list approach to exclude loading dangerous classes.
</p>
<sample src="GroovyInjectionBlocklist.java" />
</example>
<references>
<li>
Orange Tsai:
<a href="https://blog.orange.tw/2019/02/abusing-meta-programming-for-unauthenticated-rce.html">Abusing Meta Programming for Unauthenticated RCE!</a>.
</li>
<li>
Cédric Champeau:
<a href="https://melix.github.io/blog/2015/03/sandboxing.html">Improved sandboxing of Groovy scripts</a>.
</li>
<li>
Kohsuke Kawaguchi:
<a href="https://kohsuke.org/2012/04/27/groovy-secureastcustomizer-is-harmful/">Groovy SecureASTCustomizer is harmful</a>.
</li>
<li>
Welk1n:
<a href="https://github.com/welk1n/exploiting-groovy-in-Java/">Groovy Injection payloads</a>.
</li>
<li>
Charles Chan:
<a href="https://levelup.gitconnected.com/secure-groovy-script-execution-in-a-sandbox-ea39f80ee87/">Secure Groovy Script Execution in a Sandbox</a>.
</li>
<li>
Eugene:
<a href="https://stringconcat.com/en/scripting-and-sandboxing/">Scripting and sandboxing in a JVM environment</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,20 @@
/**
* @name Groovy Language injection
* @description Evaluation of a user-controlled Groovy script
* may lead to arbitrary code execution.
* @kind path-problem
* @problem.severity error
* @precision high
* @id java/groovy-injection
* @tags security
* external/cwe/cwe-094
*/
import java
import DataFlow::PathGraph
import GroovyInjectionLib
from DataFlow::PathNode source, DataFlow::PathNode sink, GroovyInjectionConfig conf
where conf.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "Groovy Injection from $@.", source.getNode(),
"this user input"

View File

@@ -0,0 +1,27 @@
public class GroovyInjection {
void injectionViaClassLoader(HttpServletRequest request) {
String script = request.getParameter("script");
final GroovyClassLoader classLoader = new GroovyClassLoader();
Class groovy = classLoader.parseClass(script);
GroovyObject groovyObj = (GroovyObject) groovy.newInstance();
}
void injectionViaEval(HttpServletRequest request) {
String script = request.getParameter("script");
Eval.me(script);
}
void injectionViaGroovyShell(HttpServletRequest request) {
GroovyShell shell = new GroovyShell();
String script = request.getParameter("script");
shell.evaluate(script);
}
void injectionViaGroovyShellGroovyCodeSource(HttpServletRequest request) {
GroovyShell shell = new GroovyShell();
String script = request.getParameter("script");
GroovyCodeSource gcs = new GroovyCodeSource(script, "test", "Test");
shell.evaluate(gcs);
}
}

View File

@@ -0,0 +1,17 @@
public class SandboxGroovyClassLoader extends ClassLoader {
public SandboxGroovyClassLoader(ClassLoader parent) {
super(parent);
}
/* override `loadClass` here to prevent loading sensitive classes, such as `java.lang.Runtime`, `java.lang.ProcessBuilder`, `java.lang.System`, etc. */
/* Note we must also block `groovy.transform.ASTTest`, `groovy.lang.GrabConfig` and `org.buildobjects.process.ProcBuilder` to prevent compile-time RCE. */
static void runWithSandboxGroovyClassLoader() throws Exception {
// GOOD: route all class-loading via sand-boxing classloader.
SandboxGroovyClassLoader classLoader = new GroovyClassLoader(new SandboxGroovyClassLoader());
Class<?> scriptClass = classLoader.parseClass(untrusted.getQueryString());
Object scriptInstance = scriptClass.newInstance();
Object result = scriptClass.getDeclaredMethod("bar", new Class[]{}).invoke(scriptInstance, new Object[]{});
}
}

View File

@@ -0,0 +1,160 @@
/**
* Provides classes and predicates for Groovy Code Injection
* taint-tracking configuration.
*/
import java
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.dataflow.TaintTracking
/** A data flow sink for Groovy expression injection vulnerabilities. */
abstract private class GroovyInjectionSink extends DataFlow::ExprNode { }
/**
* A taint-tracking configuration for unsafe user input
* that is used to evaluate a Groovy expression.
*/
class GroovyInjectionConfig extends TaintTracking::Configuration {
GroovyInjectionConfig() { this = "GroovyInjectionConfig" }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) { sink instanceof GroovyInjectionSink }
override predicate isAdditionalTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
groovyCodeSourceTaintStep(fromNode, toNode)
}
}
/** The class `groovy.lang.GroovyShell`. */
private class TypeGroovyShell extends RefType {
TypeGroovyShell() { this.hasQualifiedName("groovy.lang", "GroovyShell") }
}
/** The class `groovy.lang.GroovyCodeSource`. */
private class TypeGroovyCodeSource extends RefType {
TypeGroovyCodeSource() { this.hasQualifiedName("groovy.lang", "GroovyCodeSource") }
}
/**
* Methods in the `GroovyShell` class that evaluate a Groovy expression.
*/
private class GroovyShellMethod extends Method {
GroovyShellMethod() {
this.getDeclaringType() instanceof TypeGroovyShell and
this.getName() in ["evaluate", "parse", "run"]
}
}
private class GroovyShellMethodAccess extends MethodAccess {
GroovyShellMethodAccess() { this.getMethod() instanceof GroovyShellMethod }
}
/**
* Holds if `fromNode` to `toNode` is a dataflow step from a tainted string to
* a `GroovyCodeSource` instance, i.e. `new GroovyCodeSource(tainted, ...)`.
*/
private predicate groovyCodeSourceTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
exists(ConstructorCall gcscc |
gcscc.getConstructedType() instanceof TypeGroovyCodeSource and
gcscc = toNode.asExpr() and
gcscc.getArgument(0) = fromNode.asExpr()
)
}
/**
* A sink for Groovy Injection via the `GroovyShell` class.
*
* ```
* GroovyShell gs = new GroovyShell();
* gs.evaluate(sink, ....)
* gs.run(sink, ....)
* gs.parse(sink,...)
* ```
*/
private class GroovyShellSink extends GroovyInjectionSink {
GroovyShellSink() {
exists(GroovyShellMethodAccess ma, Argument firstArg |
ma.getArgument(0) = firstArg and
firstArg = this.asExpr() and
(
firstArg.getType() instanceof TypeString or
firstArg.getType() instanceof TypeGroovyCodeSource
)
)
}
}
/** The class `groovy.util.Eval`. */
private class TypeEval extends RefType {
TypeEval() { this.hasQualifiedName("groovy.util", "Eval") }
}
/**
* Methods in the `Eval` class that evaluate a Groovy expression.
*/
private class EvalMethod extends Method {
EvalMethod() {
this.getDeclaringType() instanceof TypeEval and
this.getName() in ["me", "x", "xy", "xyz"]
}
}
private class EvalMethodAccess extends MethodAccess {
EvalMethodAccess() { this.getMethod() instanceof EvalMethod }
Expr getArgumentExpr() { result = this.getArgument(this.getNumArgument() - 1) }
}
/**
* A sink for Groovy Injection via the `Eval` class.
*
* ```
* Eval.me(sink)
* Eval.me("p1", "p2", sink)
* Eval.x("p1", sink)
* Eval.xy("p1", "p2" sink)
* Eval.xyz("p1", "p2", "p3", sink)
* ```
*/
private class EvalSink extends GroovyInjectionSink {
EvalSink() { exists(EvalMethodAccess ma | ma.getArgumentExpr() = this.asExpr()) }
}
/** The class `groovy.lang.GroovyClassLoader`. */
private class TypeGroovyClassLoader extends RefType {
TypeGroovyClassLoader() { this.hasQualifiedName("groovy.lang", "GroovyClassLoader") }
}
/**
* A method in the `GroovyClassLoader` class that evaluates a Groovy expression.
*/
private class GroovyClassLoaderParseClassMethod extends Method {
GroovyClassLoaderParseClassMethod() {
this.getDeclaringType() instanceof TypeGroovyClassLoader and
this.hasName("parseClass")
}
}
private class GroovyClassLoaderParseClassMethodAccess extends MethodAccess {
GroovyClassLoaderParseClassMethodAccess() {
this.getMethod() instanceof GroovyClassLoaderParseClassMethod
}
}
/**
* A sink for Groovy Injection via the `GroovyClassLoader` class.
*
* ```
* GroovyClassLoader classLoader = new GroovyClassLoader();
* Class groovy = classLoader.parseClass(script);
* ```
*
* Groovy supports compile-time metaprogramming, so just calling the `parseClass`
* method is enough to achieve RCE.
*/
private class GroovyClassLoadParseClassSink extends GroovyInjectionSink {
GroovyClassLoadParseClassSink() {
exists(GroovyClassLoaderParseClassMethodAccess ma | ma.getArgument(0) = this.asExpr())
}
}

View File

@@ -0,0 +1,39 @@
import groovy.lang.GroovyClassLoader;
import groovy.lang.GroovyCodeSource;
import groovy.lang.GroovyObject;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class GroovyClassLoaderTest extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
String script = request.getParameter("script");
final GroovyClassLoader classLoader = new GroovyClassLoader();
Class groovy = classLoader.parseClass(script);
GroovyObject groovyObj = (GroovyObject) groovy.newInstance();
} catch (Exception e) {
// Ignore
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
String script = request.getParameter("script");
final GroovyClassLoader classLoader = new GroovyClassLoader();
GroovyCodeSource gcs = new GroovyCodeSource(script, "test", "Test");
Class groovy = classLoader.parseClass(gcs);
GroovyObject groovyObj = (GroovyObject) groovy.newInstance();
} catch (Exception e) {
// Ignore
}
}
}

View File

@@ -0,0 +1,41 @@
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import groovy.util.Eval;
public class GroovyEvalTest extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String script = request.getParameter("script");
Eval.me(script);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String script = request.getParameter("script");
Eval.me("test", "result", script);
}
protected void doPut(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String script = request.getParameter("script");
Eval.x("result2", script);
}
protected void doDelete(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String script = request.getParameter("script");
Eval.xy("result3", "result4", script);
}
protected void doPatch(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String script = request.getParameter("script");
Eval.xyz("result3", "result4", "aaa", script);
}
}

View File

@@ -0,0 +1,73 @@
edges
| ../../../stubs/groovy-all-3.0.7/groovy/util/Eval.java:22:29:22:51 | expression : String | ../../../stubs/groovy-all-3.0.7/groovy/util/Eval.java:23:31:23:40 | expression |
| ../../../stubs/groovy-all-3.0.7/groovy/util/Eval.java:30:44:30:66 | expression : String | ../../../stubs/groovy-all-3.0.7/groovy/util/Eval.java:31:27:31:36 | expression |
| GroovyClassLoaderTest.java:16:29:16:58 | getParameter(...) : String | GroovyClassLoaderTest.java:18:51:18:56 | script |
| GroovyClassLoaderTest.java:29:29:29:58 | getParameter(...) : String | GroovyClassLoaderTest.java:32:51:32:53 | gcs |
| GroovyEvalTest.java:12:25:12:54 | getParameter(...) : String | GroovyEvalTest.java:13:17:13:22 | script |
| GroovyEvalTest.java:12:25:12:54 | getParameter(...) : String | GroovyEvalTest.java:13:17:13:22 | script : String |
| GroovyEvalTest.java:13:17:13:22 | script : String | ../../../stubs/groovy-all-3.0.7/groovy/util/Eval.java:22:29:22:51 | expression : String |
| GroovyEvalTest.java:18:25:18:54 | getParameter(...) : String | GroovyEvalTest.java:19:35:19:40 | script |
| GroovyEvalTest.java:24:25:24:54 | getParameter(...) : String | GroovyEvalTest.java:25:27:25:32 | script |
| GroovyEvalTest.java:24:25:24:54 | getParameter(...) : String | GroovyEvalTest.java:25:27:25:32 | script : String |
| GroovyEvalTest.java:25:27:25:32 | script : String | ../../../stubs/groovy-all-3.0.7/groovy/util/Eval.java:30:44:30:66 | expression : String |
| GroovyEvalTest.java:31:25:31:54 | getParameter(...) : String | GroovyEvalTest.java:32:39:32:44 | script |
| GroovyEvalTest.java:37:25:37:54 | getParameter(...) : String | GroovyEvalTest.java:38:47:38:52 | script |
| GroovyShellTest.java:15:25:15:54 | getParameter(...) : String | GroovyShellTest.java:16:24:16:29 | script |
| GroovyShellTest.java:22:25:22:54 | getParameter(...) : String | GroovyShellTest.java:23:24:23:29 | script |
| GroovyShellTest.java:29:25:29:54 | getParameter(...) : String | GroovyShellTest.java:30:24:30:29 | script |
| GroovyShellTest.java:36:25:36:54 | getParameter(...) : String | GroovyShellTest.java:37:19:37:24 | script |
| GroovyShellTest.java:43:25:43:54 | getParameter(...) : String | GroovyShellTest.java:45:19:45:21 | gcs |
| GroovyShellTest.java:51:25:51:54 | getParameter(...) : String | GroovyShellTest.java:53:24:53:26 | gcs |
| GroovyShellTest.java:59:25:59:54 | getParameter(...) : String | GroovyShellTest.java:60:21:60:26 | script |
nodes
| ../../../stubs/groovy-all-3.0.7/groovy/util/Eval.java:22:29:22:51 | expression : String | semmle.label | expression : String |
| ../../../stubs/groovy-all-3.0.7/groovy/util/Eval.java:23:31:23:40 | expression | semmle.label | expression |
| ../../../stubs/groovy-all-3.0.7/groovy/util/Eval.java:30:44:30:66 | expression : String | semmle.label | expression : String |
| ../../../stubs/groovy-all-3.0.7/groovy/util/Eval.java:31:27:31:36 | expression | semmle.label | expression |
| GroovyClassLoaderTest.java:16:29:16:58 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| GroovyClassLoaderTest.java:18:51:18:56 | script | semmle.label | script |
| GroovyClassLoaderTest.java:29:29:29:58 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| GroovyClassLoaderTest.java:32:51:32:53 | gcs | semmle.label | gcs |
| GroovyEvalTest.java:12:25:12:54 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| GroovyEvalTest.java:13:17:13:22 | script | semmle.label | script |
| GroovyEvalTest.java:13:17:13:22 | script : String | semmle.label | script : String |
| GroovyEvalTest.java:18:25:18:54 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| GroovyEvalTest.java:19:35:19:40 | script | semmle.label | script |
| GroovyEvalTest.java:24:25:24:54 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| GroovyEvalTest.java:25:27:25:32 | script | semmle.label | script |
| GroovyEvalTest.java:25:27:25:32 | script : String | semmle.label | script : String |
| GroovyEvalTest.java:31:25:31:54 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| GroovyEvalTest.java:32:39:32:44 | script | semmle.label | script |
| GroovyEvalTest.java:37:25:37:54 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| GroovyEvalTest.java:38:47:38:52 | script | semmle.label | script |
| GroovyShellTest.java:15:25:15:54 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| GroovyShellTest.java:16:24:16:29 | script | semmle.label | script |
| GroovyShellTest.java:22:25:22:54 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| GroovyShellTest.java:23:24:23:29 | script | semmle.label | script |
| GroovyShellTest.java:29:25:29:54 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| GroovyShellTest.java:30:24:30:29 | script | semmle.label | script |
| GroovyShellTest.java:36:25:36:54 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| GroovyShellTest.java:37:19:37:24 | script | semmle.label | script |
| GroovyShellTest.java:43:25:43:54 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| GroovyShellTest.java:45:19:45:21 | gcs | semmle.label | gcs |
| GroovyShellTest.java:51:25:51:54 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| GroovyShellTest.java:53:24:53:26 | gcs | semmle.label | gcs |
| GroovyShellTest.java:59:25:59:54 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| GroovyShellTest.java:60:21:60:26 | script | semmle.label | script |
#select
| ../../../stubs/groovy-all-3.0.7/groovy/util/Eval.java:23:31:23:40 | expression | GroovyEvalTest.java:12:25:12:54 | getParameter(...) : String | ../../../stubs/groovy-all-3.0.7/groovy/util/Eval.java:23:31:23:40 | expression | Groovy Injection from $@. | GroovyEvalTest.java:12:25:12:54 | getParameter(...) | this user input |
| ../../../stubs/groovy-all-3.0.7/groovy/util/Eval.java:31:27:31:36 | expression | GroovyEvalTest.java:24:25:24:54 | getParameter(...) : String | ../../../stubs/groovy-all-3.0.7/groovy/util/Eval.java:31:27:31:36 | expression | Groovy Injection from $@. | GroovyEvalTest.java:24:25:24:54 | getParameter(...) | this user input |
| GroovyClassLoaderTest.java:18:51:18:56 | script | GroovyClassLoaderTest.java:16:29:16:58 | getParameter(...) : String | GroovyClassLoaderTest.java:18:51:18:56 | script | Groovy Injection from $@. | GroovyClassLoaderTest.java:16:29:16:58 | getParameter(...) | this user input |
| GroovyClassLoaderTest.java:32:51:32:53 | gcs | GroovyClassLoaderTest.java:29:29:29:58 | getParameter(...) : String | GroovyClassLoaderTest.java:32:51:32:53 | gcs | Groovy Injection from $@. | GroovyClassLoaderTest.java:29:29:29:58 | getParameter(...) | this user input |
| GroovyEvalTest.java:13:17:13:22 | script | GroovyEvalTest.java:12:25:12:54 | getParameter(...) : String | GroovyEvalTest.java:13:17:13:22 | script | Groovy Injection from $@. | GroovyEvalTest.java:12:25:12:54 | getParameter(...) | this user input |
| GroovyEvalTest.java:19:35:19:40 | script | GroovyEvalTest.java:18:25:18:54 | getParameter(...) : String | GroovyEvalTest.java:19:35:19:40 | script | Groovy Injection from $@. | GroovyEvalTest.java:18:25:18:54 | getParameter(...) | this user input |
| GroovyEvalTest.java:25:27:25:32 | script | GroovyEvalTest.java:24:25:24:54 | getParameter(...) : String | GroovyEvalTest.java:25:27:25:32 | script | Groovy Injection from $@. | GroovyEvalTest.java:24:25:24:54 | getParameter(...) | this user input |
| GroovyEvalTest.java:32:39:32:44 | script | GroovyEvalTest.java:31:25:31:54 | getParameter(...) : String | GroovyEvalTest.java:32:39:32:44 | script | Groovy Injection from $@. | GroovyEvalTest.java:31:25:31:54 | getParameter(...) | this user input |
| GroovyEvalTest.java:38:47:38:52 | script | GroovyEvalTest.java:37:25:37:54 | getParameter(...) : String | GroovyEvalTest.java:38:47:38:52 | script | Groovy Injection from $@. | GroovyEvalTest.java:37:25:37:54 | getParameter(...) | this user input |
| GroovyShellTest.java:16:24:16:29 | script | GroovyShellTest.java:15:25:15:54 | getParameter(...) : String | GroovyShellTest.java:16:24:16:29 | script | Groovy Injection from $@. | GroovyShellTest.java:15:25:15:54 | getParameter(...) | this user input |
| GroovyShellTest.java:23:24:23:29 | script | GroovyShellTest.java:22:25:22:54 | getParameter(...) : String | GroovyShellTest.java:23:24:23:29 | script | Groovy Injection from $@. | GroovyShellTest.java:22:25:22:54 | getParameter(...) | this user input |
| GroovyShellTest.java:30:24:30:29 | script | GroovyShellTest.java:29:25:29:54 | getParameter(...) : String | GroovyShellTest.java:30:24:30:29 | script | Groovy Injection from $@. | GroovyShellTest.java:29:25:29:54 | getParameter(...) | this user input |
| GroovyShellTest.java:37:19:37:24 | script | GroovyShellTest.java:36:25:36:54 | getParameter(...) : String | GroovyShellTest.java:37:19:37:24 | script | Groovy Injection from $@. | GroovyShellTest.java:36:25:36:54 | getParameter(...) | this user input |
| GroovyShellTest.java:45:19:45:21 | gcs | GroovyShellTest.java:43:25:43:54 | getParameter(...) : String | GroovyShellTest.java:45:19:45:21 | gcs | Groovy Injection from $@. | GroovyShellTest.java:43:25:43:54 | getParameter(...) | this user input |
| GroovyShellTest.java:53:24:53:26 | gcs | GroovyShellTest.java:51:25:51:54 | getParameter(...) : String | GroovyShellTest.java:53:24:53:26 | gcs | Groovy Injection from $@. | GroovyShellTest.java:51:25:51:54 | getParameter(...) | this user input |
| GroovyShellTest.java:60:21:60:26 | script | GroovyShellTest.java:59:25:59:54 | getParameter(...) : String | GroovyShellTest.java:60:21:60:26 | script | Groovy Injection from $@. | GroovyShellTest.java:59:25:59:54 | getParameter(...) | this user input |

View File

@@ -0,0 +1 @@
experimental/Security/CWE/CWE-094/GroovyInjection.ql

View File

@@ -0,0 +1,63 @@
import groovy.lang.GroovyCodeSource;
import groovy.lang.GroovyShell;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class GroovyShellTest extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
GroovyShell shell = new GroovyShell();
String script = request.getParameter("script");
shell.evaluate(script);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
GroovyShell shell = new GroovyShell();
String script = request.getParameter("script");
shell.evaluate(script, "test");
}
protected void doPut(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
GroovyShell shell = new GroovyShell();
String script = request.getParameter("script");
shell.evaluate(script, "test", "test2");
}
protected void doOptions(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
GroovyShell shell = new GroovyShell();
String script = request.getParameter("script");
shell.run(script, "_", new String[]{});
}
protected void doHead(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
GroovyShell shell = new GroovyShell();
String script = request.getParameter("script");
GroovyCodeSource gcs = new GroovyCodeSource(script, "test", "Test");
shell.run(gcs, new String[]{});
}
protected void doDelete(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
GroovyShell shell = new GroovyShell();
String script = request.getParameter("script");
GroovyCodeSource gcs = new GroovyCodeSource(script, "test", "Test");
shell.evaluate(gcs);
}
protected void doPatch(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
GroovyShell shell = new GroovyShell();
String script = request.getParameter("script");
shell.parse(script);
}
}

View File

@@ -1 +1,2 @@
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3:${testdir}/../../../../stubs/mvel2-2.4.7:${testdir}/../../../../stubs/jsr223-api:${testdir}/../../../../stubs/apache-commons-jexl-2.1.1:${testdir}/../../../../stubs/apache-commons-jexl-3.1:${testdir}/../../../../stubs/scriptengine:${testdir}/../../../../stubs/java-ee-el:${testdir}/../../../../stubs/juel-2.2
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3:${testdir}/../../../../stubs/mvel2-2.4.7:${testdir}/../../../../stubs/jsr223-api:${testdir}/../../../../stubs/apache-commons-jexl-2.1.1:${testdir}/../../../../stubs/apache-commons-jexl-3.1:${testdir}/../../../../stubs/scriptengine:${testdir}/../../../../stubs/java-ee-el:${testdir}/../../../../stubs/juel-2.2:${testdir}/../../../stubs/groovy-all-3.0.7:${testdir}/../../../../stubs/servlet-api-2.4

View File

@@ -0,0 +1,32 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package groovy.lang;
public class GroovyClassLoader {
public GroovyClassLoader() {
}
public Class parseClass(String text) {
return null;
}
public Class parseClass(GroovyCodeSource gcs) {
return null;
}
}

View File

@@ -0,0 +1,23 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package groovy.lang;
public class GroovyCodeSource {
public GroovyCodeSource(String script, String param1, String param2) {}
}

View File

@@ -0,0 +1,21 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package groovy.lang;
public interface GroovyObject {}

View File

@@ -0,0 +1,66 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package groovy.lang;
import java.util.*;
public class GroovyShell {
public GroovyShell() {}
public Object evaluate(GroovyCodeSource codeSource) {
return null;
}
public Object evaluate(String scriptText) {
return null;
}
public Object evaluate(String scriptText, String fileName) {
return null;
}
public Object evaluate(String scriptText, final String fileName, final String codeBase) {
return null;
}
public Object run(String scriptText, String fileName, List<String> list) {
return null;
}
public Object run(String scriptText, String fileName, String[] args) {
return null;
}
public Object run(GroovyCodeSource source, List<String> args) {
return null;
}
public Object run(GroovyCodeSource source, String[] args) {
return null;
}
public Script parse(String scriptText) {
return null;
}
public Script parse(final String scriptText, final String fileName) {
return null;
}
}

View File

@@ -0,0 +1,22 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package groovy.lang;
public abstract class Script {
}

View File

@@ -0,0 +1,41 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package groovy.util;
public class Eval {
public static Object me(final String expression) {
return me(null, null, expression);
}
public static Object me(final String symbol, final Object object, final String expression) {
return null;
}
public static Object x(final Object x, final String expression) {
return me("x", x, expression);
}
public static Object xy(final Object x, final Object y, final String expression) {
return null;
}
public static Object xyz(final Object x, final Object y, final Object z, final String expression) {
return null;
}
}