Java RASP简单实现

2024-11-18 12 0

RASP 技术通常内置在一个应用程序或应用程序运行时环境中,能够控制应用程序的执行,并检测漏洞以防止实时攻击,当应用程序开始运行时,RASP 可以通过分析应用程序的行为和该行为的上下文,保护其不受恶意输入或行为的影响。RASP 通过使应用程序持续检测自身的行为,可以立即识别和缓解攻击,且无需人工干预。在Java应用程序中,通常使用Agent来进行实现。

一 前置知识

Agent

agent分为preagent和agentmain,其主要差别为一个是在应用程序启动前进行加载,一个是在启动中也可以进行加载,agentmain的使用更加广泛,本文也主要使用agentmain(了解过agent内存马对这块内容会比较熟悉)

创建一个agent,新建一个类,实现agentmain方法,方法中body可以打印一句话

Java RASP简单实现插图

项目中添加一个工件

Java RASP简单实现插图1

修改MANIFEST.MF文件,主要添加Agent-Class,指定为我们的类

Java RASP简单实现插图2

正常构建工件,即可得到jar包

Java RASP简单实现插图3

想要将这个agent注入到别的程序中,我们还需要一个注入器(需要tools.jar的依赖,可手动导入)

代码:

apache.catalina.startup表示我现在注入的是tomcat,这里牵扯到VirtualMachine这个类的使用,可以看我之前agent内存马的文章

import com.sun.tools.attach.*;

import java.io.IOException;
import java.util.List;

public class Main {
        public static void main(String[] args) throws IOException, AttachNotSupportedException, AgentLoadException, AgentInitializationException {
                List<VirtualMachineDescriptor> list = VirtualMachine.list();
                for (VirtualMachineDescriptor virtualMachineDescriptor : list) {
                        System.out.println(virtualMachineDescriptor.displayName());
                        if (virtualMachineDescriptor.displayName().contains("apache.catalina.startup")) {
                                VirtualMachine attach = VirtualMachine.attach(virtualMachineDescriptor);
                                attach.loadAgent("路径\\agent01.jar");
                        }

                }
        }
}

当注入成功,会直接执行agentmain中自定义的代码

Java RASP简单实现插图4

Runtime.getRuntime().exec()本质调用

这里直接看一下,可以发现其实调用的还是java.lang.ProcessImpl的start方法和java.lang.Process

Java RASP简单实现插图5

Java RASP简单实现插图6

贴一个命令执行流程的图

Java RASP简单实现插图7

二 RASP实现

命令执行hook

继续修改agentmain代码,这里涉及 Instrumentation 和javassist(修改字节码)类,

为什么不直接hook Runtime.getRuntime.exec的原因是冰蝎执行命令这里我看到不会通过Runtime方法(如果真实常见应该是全部hook掉)

版本1,只能加载一次,之后不会再触发,通过instrumentation.addTransformer向 JVM 注册一个ClassFileTransformer实例

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;
import java.util.Arrays;

public class AgentDemo implements ClassFileTransformer {
    private static final String TARGET_CLASS_NAME = "java.lang.ProcessImpl";

    public static void agentmain(String agentArgs, Instrumentation instrumentation) {
        instrumentation.addTransformer(new AgentDemo(), true);
    }

@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) {
System.out.println(className.replace('/', '.'));
if (!TARGET_CLASS_NAME.equals(className.replace('/', '.'))) {
return classfileBuffer; // 不是目标类,直接返回
}

try {
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.getCtClass(TARGET_CLASS_NAME);

CtMethod execMethod = ctClass.getDeclaredMethod("start");
CtMethod[] methods = ctClass.getDeclaredMethods();
String insertBefore = "System.out.println(\"ProcessImpl start method is called\");";
execMethod.insertBefore(insertBefore);

return ctClass.toBytecode();
} catch (Exception e) {
e.printStackTrace();
}
return classfileBuffer; // 发生异常,返回原始字节码
}
}

版本2

每次遇到目标hook类都会重加载,通过instrumentation.retransformClasses实现

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;
import java.security.ProtectionDomain;
import java.util.Arrays;

public class AgentDemo implements ClassFileTransformer {
    private static final String TARGET_CLASS_NAME = "java.lang.ProcessImpl";

    public static void agentmain(String agentArgs, Instrumentation instrumentation) throws UnmodifiableClassException {
        // 获取所有已加载的类
        Class[] allLoadedClasses = instrumentation.getAllLoadedClasses();
        for (Class<?> clazz : allLoadedClasses) {
            if (clazz.getName().equals(TARGET_CLASS_NAME)) {
                // 对已加载的类应用变换
                instrumentation.retransformClasses(clazz);
            }
        }
        // 添加变换器以应用于之后加载的类
        instrumentation.addTransformer(new AgentDemo(), true);
    }

    @Override
    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) {
        System.out.println(className.replace('/', '.'));
        if (!TARGET_CLASS_NAME.equals(className.replace('/', '.'))) {
            return classfileBuffer; // 不是目标类,直接返回
        }

        try {
            ClassPool pool = ClassPool.getDefault();
            CtClass ctClass = pool.getCtClass(TARGET_CLASS_NAME);

            CtMethod execMethod = ctClass.getDeclaredMethod("start");
            CtMethod[] methods = ctClass.getDeclaredMethods();
            String insertBefore = "System.out.println(\"ProcessImpl start method is called\");";
            execMethod.insertBefore(insertBefore);

            return ctClass.toBytecode();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return classfileBuffer; // 发生异常,返回原始字节码
    }
}

好的,现在启动一个tomcat,注射器加载一下agent,可以看到当执行命令前被检测到,先执行了我们通过javassist写的内容

Java RASP简单实现插图8

这就是RASP的基本原理,我们可以自定义检测Hook的函数,如果是恶意操作直接关闭该访问

文件读写Hook

其实只是更换一个hook的类

其实java中对文件操作类有特别多java.io.File、java.io.FileInputStream、java.io.FileOutputStream,还有很多,以java.io.File为例:

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;
import java.security.ProtectionDomain;
import java.util.Arrays;

import javassist.*;

public class AgentDemo implements ClassFileTransformer {
    private static final String TARGET_CLASS_NAME = "java.io.File";

    public static void agentmain(String agentArgs, Instrumentation instrumentation) throws UnmodifiableClassException {
        // 获取所有已加载的类
        Class[] allLoadedClasses = instrumentation.getAllLoadedClasses();
        for (Class<?> clazz : allLoadedClasses) {
            if (clazz.getName().equals(TARGET_CLASS_NAME)) {
                // 对已加载的类应用变换
                instrumentation.retransformClasses(clazz);
            }
        }
        // 添加变换器以应用于之后加载的类
        instrumentation.addTransformer(new AgentDemo(), true);
    }

    @Override
    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
                            ProtectionDomain protectionDomain, byte[] classfileBuffer) {
        if (className.equals(TARGET_CLASS_NAME.replace('.', '/'))) {
            try {
                ClassPool pool = ClassPool.getDefault();
                CtClass ctClass = pool.getCtClass(TARGET_CLASS_NAME);

                // 获取 createNewFile 方法
                CtMethod createNewFileMethod = ctClass.getDeclaredMethod("createNewFile");

                // 在 createNewFile 方法前后插入代码
                String beforeCode = "System.out.println(\"Before createNewFile: \";)";
                createNewFileMethod.insertBefore(beforeCode);
                String afterCode = "System.out.println(\"After createNewFile:  \");";
                createNewFileMethod.insertAfter(afterCode);

                return ctClass.toBytecode();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return classfileBuffer; // 发生异常或不是目标类,返回原始字节码
    }

}

更多的不在展示,大致思路就是hook不同的类,可以实现的效果

  1. 文件系统防御(目录遍历、文件读、写、重命名、移动等)
  2. SQL查询防御
  3. XML实体注入防御
  4. 恶意表达式执行防御(Ognl、SpEL、MVEL2等)
  5. 恶意WebShell请求拦截
  6. 恶意文件上传
  7. 本地命令执行
  8. 反序列化攻击(Java、XML、Json)
  9. SSRF攻击

三 绕过思路

现在绕过思路基本就是两个

  • 寻找没有被限制的类或者函数来绕过(类似绕过黑名单)

这个其实就是上面File读写的问题,尽量覆盖所有的或者hook更加深入底层的东西

  • 利用更底层的技术进行绕过,比如上面图中直接hook c代码(难度较大)
  • JNI 绕过 RASP(通过编译so和dll文件的方式)
  • 创建新线程的方式(如果有黑名单无法绕过,但是可以绕过堆栈)

4A评测 - 免责申明

本站提供的一切软件、教程和内容信息仅限用于学习和研究目的。

不得将上述内容用于商业或者非法用途,否则一切后果请用户自负。

本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。

如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。敬请谅解!

程序来源网络,不确保不包含木马病毒等危险内容,请在确保安全的情况下或使用虚拟机使用。

侵权违规投诉邮箱:4ablog168#gmail.com(#换成@)

相关文章

webpack打包站点,js文件名批量获取思路
加密对抗靶场enctypt——labs通关
【论文速读】| 注意力是实现基于大语言模型的代码漏洞定位的关键
蓝队技术——Sysmon识别检测宏病毒
内网渗透学习|powershell上线cs
LLM attack中的API调用安全问题及靶场实践

发布评论