字体对话框java实验_Java Web安全 || Java基础 sun.misc.Unsafe

点击上方“凌天实验室”,“星标或置顶公众号”

漏洞、技术还是其他,我都想第一时间和你分享

55cab92a3b001f44e8e9a00836d198d3.png

【历史】已连载更新全部内容:【菜单栏】-【JAVA SEC】

sun.misc.Unsafe是Java底层API(仅限Java内部使用,反射可调用)提供的一个神奇的Java类,Unsafe提供了非常底层的内存、CAS、线程调度、类、对象等操作、Unsafe正如它的名字一样它提供的几乎所有的方法都是不安全的,本节只讲解如何使用Unsafe定义Java类、创建类实例。

7a6d95da0dffa55dcb89d7488c523b21.png

如何获取Unsafe对象

Unsafe是Java内部API,外部是禁止调用的,在编译Java类时如果检测到引用了Unsafe类也会有禁止使用的警告:Unsafe是内部专用 API, 可能会在未来发行版中删除

sun.misc.Unsafe代码片段:

import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;

public final class Unsafe {

private static final Unsafe theUnsafe;

static {
theUnsafe = new Unsafe();
省去其他代码......
}

private Unsafe() {
}

@CallerSensitive
public static Unsafe getUnsafe() {
Class var0 = Reflection.getCallerClass();
if (var0.getClassLoader() != null) {
throw new SecurityException("Unsafe");
} else {
return theUnsafe;
}
}

省去其他代码......
}

由上代码片段可以看到,Unsafe类是一个不能被继承的类且不能直接通过new的方式创建Unsafe类实例,如果通过getUnsafe方法获取Unsafe实例还会检查类加载器,默认只允许Bootstrap Classloader调用。

既然无法直接通过Unsafe.getUnsafe()的方式调用,那么可以使用反射的方式去获取Unsafe类实例。

反射获取Unsafe类实例代码片段:

// 反射获取Unsafe的theUnsafe成员变量

当然我们也可以用反射创建Unsafe类实例的方式去获取Unsafe对象:

// 获取Unsafe无参构造方法
Constructor constructor = Unsafe.class.getDeclaredConstructor();

// 修改构造方法访问权限
constructor.setAccessible(true);

// 反射创建Unsafe类实例,等价于 Unsafe unsafe1 = new Unsafe();
Unsafe unsafe1 = (Unsafe) constructor.newInstance();

获取到了Unsafe对象我们就可以调用内部的方法了。

7a6d95da0dffa55dcb89d7488c523b21.png

allocateInstance无视构造方法创建类实例

假设我们有一个叫com.anbai.sec.unsafe.UnSafeTest的类,因为某种原因我们不能直接通过反射的方式去创建UnSafeTest类实例,那么这个时候使用UnsafeallocateInstance方法就可以绕过这个限制了。

UnSafeTest代码片段:

public class UnSafeTest {

private UnSafeTest() {
// 假设RASP在这个构造方法中插入了Hook代码,我们可以利用Unsafe来创建类实例
System.out.println("init...");
}

}

使用Unsafe创建UnSafeTest对象:

// 使用Unsafe创建UnSafeTest类实例
UnSafeTest test = (UnSafeTest) unsafe1.allocateInstance(UnSafeTest.class);

Google的GSON库在JSON反序列化的时候就使用这个方式来创建类实例,在渗透测试中也会经常遇到这样的限制,比如RASP限制了java.io.FileInputStream类的构造方法导致我们无法读文件或者限制了UNIXProcess/ProcessImpl类的构造方法导致我们无法执行本地命令等。

7a6d95da0dffa55dcb89d7488c523b21.png

defineClass直接调用JVM创建类对象

ClassLoader章节我们讲了通过ClassLoader类的defineClass0/1/2方法我们可以直接向JVM中注册一个类,如果ClassLoader被限制的情况下我们还可以使用UnsafedefineClass方法来实现同样的功能。

Unsafe提供了一个通过传入类名、类字节码的方式就可以定义类的defineClass方法:

public native Class defineClass(String var1, byte[] var2, int var3, int var4);

public native Class> defineClass(String var1, byte[] var2, int var3, int var4, ClassLoader var5, ProtectionDomain var6);

使用Unsafe创建TestHelloWorld对象:

// 使用Unsafe向JVM中注册com.anbai.sec.classloader.TestHelloWorld类
Class helloWorldClass = unsafe1.defineClass(TEST_CLASS_NAME, TEST_CLASS_BYTES, 0, TEST_CLASS_BYTES.length);

或调用需要传入类加载器和保护域的方法:

// 获取系统的类加载器
ClassLoader classLoader = ClassLoader.getSystemClassLoader();

// 创建默认的保护域
ProtectionDomain domain = new ProtectionDomain(
new CodeSource(null, (Certificate[]) null), null, classLoader, null
);

// 使用Unsafe向JVM中注册com.anbai.sec.classloader.TestHelloWorld类
Class helloWorldClass = unsafe1.defineClass(
TEST_CLASS_NAME, TEST_CLASS_BYTES, 0, TEST_CLASS_BYTES.length, classLoader, domain
);

Unsafe还可以通过defineAnonymousClass方法创建内部类,这里不再多做测试。

注意:

这个实例仅适用于Java 8以前的版本如果在Java 8中应该使用应该调用需要传类加载器和保护域的那个方法。Java 11开始Unsafe类已经把defineClass方法移除了(defineAnonymousClass方法还在),虽然可以使用java.lang.invoke.MethodHandles.Lookup.defineClass来代替,但是MethodHandles只是间接的调用了ClassLoaderdefineClass,所以一切也就回到了ClassLoader

**如果您在阅读文章的时候发现任何问题都可以通过Vchat与我们联系,也欢迎大家加入javasec微信群一起交流。

Vchat获取方式:对话框发送“javasec”

b8d4e778b236afcfe7cd873d31e72b22.png 42095725f480163798db0a4d561a1fb1.png凌天实验室

凌天实验室,是安百科技旗下针对应用安全领域进行攻防研究的专业技术团队,其核心成员来自原乌云创始团队及社区知名白帽子,团队专业性强、技术层次高且富有实战经验。实验室成立于2016年,发展至今团队成员已达35人,在应用安全领域深耕不辍,向网络安全行业顶尖水平攻防技术团队的方向夯实迈进。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值