Unsafe

sun.misc.Unsafe

sun.misc.Unsafe提供了一些底层操作,如内存、CAS、类、对象

Unsafe是Java内部API,不允许外部调用

/*
A collection of methods for performing low-level, unsafe operations. Although the class and all methods are public, use of this class is limited because only trusted code can obtain instances of it.
*/
public final class Unsafe {
    private Unsafe() {}

    private static final Unsafe theUnsafe = new Unsafe();
    
    @CallerSensitive
    public static Unsafe getUnsafe() {
        Class<?> caller = Reflection.getCallerClass();
        if (!VM.isSystemDomainLoader(caller.getClassLoader()))
            throw new SecurityException("Unsafe");
        return theUnsafe;
    }
    
}

Unsafe采用了单例模式,其getUnsafe()方法会先判断调用者(Reflection.getCallerClass();)的类加载器classLoader是否为Bootstrap Classloader

可以使用反射来获取Unsafe对象

allocateInstance

若RASP限制了某些类的构造方法(比如TrAXFilter(加载字节码)、ProcessImpl(Windows命令执行)、UnixProcess(Linux命令执行))

可以用UnsafeallocateInstance方法绕过这个限制

Google的GSON库在JSON反序列化的时候就使用这个方式来创建类实例

image-20230506135841815

绕过命令执行限制

Windows版本:

Linux版本:

注意这个方法并不会执行任何构造方法

有时候使用反射去创建实例时,会遇到各种复杂的类依赖关系,此时也可以考虑用这个去实例化对象

内存层面修改值

在JVM中,对实例的Field进行了有规律的存储,通过一个偏移量可以从内存中找到相应的Field值

Unsafe提供两个方法来获取Field的偏移量

staticFieldOffset(Field var1)objectFieldOffset(Field var1)

获取偏移量后可以调用putObjectputInt等方法来修改对象的成员值

Fieldset方法被限制时,可以考虑这种方法绕过

但对final修饰的字段貌似改不了

defineClass

Unsafe提供了一个defineClass方法,传入类名、类字节码可以在JVM中注册一个类

image-20230506140538855

注意Unsafe#defineClass只能在JVM中define一个类,不会加载这个类,所以最后通过Class.forName来触发其静态代码块

defineAnonymousClass

defineAnonymousClass可以创建一个内部类

这个类的名字设置时甚至可以是已存在的类名,由于java动态编译特性会在内存中生成新的类名

无法通过Class.forName获取这个类的(do not make it known to the class loader

这个类的classloader为null

image-20230506142538288

打印出类名为java.lang.String/1645995473,并弹出计算器

Java 11 把UnsafedefineClass方法移除了,但defineAnonymousClass还在

Close RASP

一旦攻击者拿到了一个代码执行权限,那么他便可以通过反射的方式取得RASP运行在内存中的开关变量(多为boolean或者AtomicBoolean类型),并把它由true修改为false,就可以使RASP得的防护完全失效。开关变量只是其中一个思路,当然有更多的方法去破坏RASP的运行模式,如置空检测逻辑代码(如果RASP使用了js、lua等别的引擎),置空黑名单、添加白名单

Summary

  • 内存层面修改对象的字段

    • 绕反射限制

    • 关闭RASP开关

  • 自定义类

    • 更加隐蔽的内存马

    • defineAnonymousClass生成的类无法通过反射获取其内部信息,且类加载器为Bootstrap ClassLoader,会被认为jdk自带的类

Reference

Last updated

Was this helpful?