RASP hook插桩原理解析

news2025/1/10 1:52:02
  • javaagent技术,实现提前加载类字节码
  • 实现hook,插桩技术
    • javassist技术
    • ASM字节码技术
  • 像加载jar,有两种方式
    • premain启动前加载:每次变动jar包内容,都需要进行重启服务器
    • 利用java的动态attch加载原理,采用probe技术,实现动态加载jar包:容易重写方法

十分清晰的插桩流程图(使用了javaAgent、插桩技术)


java文件运行原理

OpenRASP是怎么进行插桩操作

  • 启动时候进行了插桩操作,当有类被 ClassLoader 加载时候,所以会把该类的字节码先交给自定义的 Transformer 处理
  • 自定义 Transformer 会判断该类是否为需要 hook 的类,如果是会将该类交给 javassist 字节码处理框架进行处理,javassist
  • javassist 框架会将类的字节码依照事件驱动模型逐步解析每个方法,当触发了我们需要 hook 的方法,我们会在方法的开头或者结尾插入进入检测函数的字节码
  • 把 hook 好的字节码返回给 transformer 从而载入虚拟机
个人理解【插桩】
  • 无论是哪种插桩方式,都是以类加载后,修改class文件的字节码为主;
  • 可以看出来,OpenRasp是借助javassist进行对关注类两头监听,查看里面的行为是否违规;
  • 大致流程就是一个关注类被加载了,拿这个类的class文件,对文件的字节码进行修改成自己想要的class,然后在放回去,载入JVM,进行执行,原本那个class文件就直接放弃了;
  • 好处就是源代码没有修改,只是修改了class文件。

注意:OpenRASP是启动前加载的,所以所有的类模块加载都是在启动前就已经换成自己想要的字节码了,每当调用关注类时,就不会调用原来的代码,而是调用编写好的代码强化的代码模块

OpenRasp是如何进行请求处理

  1. 服务器收到一个请求,从而进入了服务器的请求 hook 点
  2. 服务器发起SQL查询
  3. 进入 SQLStatementHook 点,我们挂钩了 execute、executeUpdate、executeQuery 等方法,从该方法进入检测流程如下:
    1. 判断当前线程是否为请求线程(第一步标记的),如果是继续下面检测
    2. 采集 connection_id(这个字段仅JDBC支持)、SQL 语句以及数据库类型 等信息
    3. 构建参数信息,调用本地插件和 JS 插件进行安全检测,JS 插件由 Rhino 引擎执行,Rhino 引擎执行是 mozilla 为 java 提供的 JavaScript引擎,该引擎会将 JS 代码编译为 java 的 class 字节码在 JVM 中运行,Rhino 引擎文档
    4. 根据插件的执行结果决定是拦截请求、放行还是仅打印日志
  4. 进入 SQLResultSetHook 点,我们挂钩了 resultSet.next 方法
    1. 调用本地插件检查是否发生拖库行为,默认策略为一次查询结果超过500条就报警
  5. 若决定拦截攻击
    1. 输出报警日志到 logs/alarm.log
    2. 如果header还没有发出,默认使用 302 跳转到拦截页面
    3. 如果body还没有发出,则重置未发送的body
    4. 输出自定义拦截页面跳转js脚本


javassist技术

在一个测试jar包执行前,提前执行编写好的permain函数,将原本的测试jar的字节码,替换成自己想要的字节码,然后再放回去,JVM只执行我修改好的class文件,转义后,这个代码就拥有自我监控和拦截功能,就达成了无入侵自我保护。

ASM技术和Javassist技术的差异

先说说相同点
这两个技术都是java字节码修改技术,都可以对未加入JVM的class文件,进行修改。
不同之处
ASM主要是通过字节码进行修改,而javassist是通过java代码进行修改的
直接看下他们之间代码,就懂了
同一份java代码,看下他们二者的区别

// 修改前
    public void test(String args) {
        System.out.println("rasp Test,正常通过!!");
    }
// 修改后
public void test(String var1) {
        SqlFilter var3 = new SqlFilter();
        if (var3.filter(var1)) {
            throw new SQLException("invalid sql because of security check");
        } else {
            System.out.println("rasp Test,正常通过!!");
        }
    }

// 添加部分
    SqlFilter var3 = new SqlFilter();
            if (var3.filter(var1)) {
                throw new SQLException("invalid sql because of security check");
            } else {
               // 原本代码 XXXX
            }

看下ASM进行插桩

        mv.visitTypeInsn(NEW,"com/wu/javaagent01/filter/SqlFilter");
        mv.visitInsn(DUP);
        mv.visitMethodInsn(INVOKESPECIAL,"com/wu/javaagent01/filter/SqlFilter","<init>","()V",false);
        mv.visitVarInsn(ASTORE,3);
        mv.visitVarInsn(ALOAD,3);
        mv.visitVarInsn(ALOAD,1);
        mv.visitMethodInsn(INVOKEVIRTUAL,"com/wu/javaagent01/filter/SqlFilter", "filter","(Ljava/lang/Object;)Z",false);
        mv.visitJumpInsn(IFEQ, l92);
        mv.visitTypeInsn(NEW, "java/sql/SQLException");
        mv.visitInsn(DUP);
        mv.visitLdcInsn("invalid sql because of security check");
        mv.visitMethodInsn(INVOKESPECIAL, "java/sql/SQLException", "<init>", "(Ljava/lang/String;)V", false);
        mv.visitInsn(ATHROW);
        mv.visitLabel(l92);
		mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);

再看看javassist对这个代码如何插桩的

ClassPool classPool = ClassPool.getDefault();
CtClass ctClass = classPool.get("YourClassName"); // 替换成你的类名

CtMethod ctMethod = ctClass.getDeclaredMethod("checkListFiles");

CtClass exceptionClass = classPool.get("java.sql.SQLException");

// 创建异常抛出代码块
CtConstructor exceptionConstructor = exceptionClass.getDeclaredConstructor(new CtClass[] { classPool.get("java.lang.String") });
CtConstructor ctConstructor = ctClass.getClassInitializer();
ctConstructor.insertAfter("{" +
    "if (condition) {" +
    "    try {" +
    "        throw new java.sql.SQLException(\"invalid sql because of security check\");" +
    "    } catch (java.sql.SQLException e) {" +
    "        e.printStackTrace();" +
    "    }" +
    "}");
    // 保存修改后的字节码
    ctClass.writeFile();
} catch (Exception e) {
    e.printStackTrace();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1037786.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

查询统计当前日期往前推近七天每天的记录数

1、查询统计当前日期往前推近七天每天的记录数。 并且如果某一天没有数据&#xff0c;则该天不会显示在结果集中&#xff0c;也不会用零值补充 SELECT date_format(create_time, %Y-%m-%d), count(*) FROM your_table WHERE create_time > date_sub(curdate(), interval 6…

恒合仓库 - 采购单管理模块

采购单管理模块 文章目录 采购单管理模块一、添加采购单(核心)1.1 采购流程1.2 采购单实体类1.3 添加采购单1.3.1 Mapper1.3.2 Service1.3.3 Controller1.3.4 效果图 二、采购单管理模块2.1 仓库数据回显2.1.1 Mapper2.1.2 Service2.1.3 Controller2.1.4 效果图 2.2 采购单列表…

Docker - Docker启动的MySql修改密码

基于上篇文章《Docker - Docker安装MySql并启动》&#xff0c;在Docker中启动了mysql服务&#xff0c;但是密码设置成了123456&#xff0c;想起来学生时代数据库被盗走&#xff0c;然后邮箱收到被勒索BTC的场景还历历在目&#x1f62d;&#xff0c;密码不能再设置这么简单了啊&…

【prometheus+grafana】快速入门搭建-服务监控各插件及企业微信告警

目录 1. 安装qywechat_webhook插件通知企业微信 1.1. 新建目录/opt/prometheus/qywechathook/conf 1.2. 新建编辑wx.js文件 1.3. 运行启动容器 1.4. 查看容器启动情况 1.5 企业微信通知地址为&#xff1a; 2. 安装altermanager 2.1. 下载altermanager 2.2. 解压alterm…

Linux 远程登录(Xshell7)

为什么需要远程登录Linux&#xff1f;因为通常在公司做开发的时候&#xff0c;Linux 一般作为服务器使用&#xff0c;而服务器一般放在机房&#xff0c;linux服务器是开发小组共享&#xff0c;且正式上线的项目是运行在公网&#xff0c;因此需要远程登录到Liux进行项日管理或者…

LeetCode算法二叉树—二叉树的中序遍历

目录 94. 二叉树的中序遍历 - 力扣&#xff08;LeetCode&#xff09; 代码&#xff1a; 运行结果&#xff1a; 给定一个二叉树的根节点 root &#xff0c;返回 它的 中序 遍历 。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,3,2]示例 2&am…

Linux--线程 创建、等待、退出

Linux上线程开发API概要 多线程开发的最基本概念主要包含&#xff1a;线程&#xff0c;互斥锁&#xff0c;条件。   线程 3 种操作&#xff1a;线程的创建&#xff0c;退出&#xff0c;等待。   互斥锁 4 种操作&#xff1a;创建&#xff0c;销毁&#xff0c;加锁和解锁。…

iterm2 配置自动登录跳板机,无需输入密码和google验证码

1、准备&#xff1a;编写Python脚本计算生成google身份验证码&#xff0c;参考python3 实现 google authenticator 认证/校验_我要买GTR45的博客-CSDN博客 脚本拿来就可以用&#xff0c;只需要替换脚本中的secret字段的值为自己的密钥即可 2、在~/.ssh/目录下编写expect脚本 …

多台群晖实现按计划WOL网络自动唤醒数据冷备份

几年前买了2盘位的DS218&#xff0c;但是随着照片的增加已经不够用。年中购入了4盘位的群晖DS923、2块16T西数数企业级硬盘、1块2T intel企业级 SSD 1.什么是冷备份 冷备是离线备份&#xff0c;备份好的数据可以单独存取&#xff0c;定期冷备可以保证数据安全&#xff0c;适合…

怎样快速打开github.com

1访问这个网站很慢是因为有DNS污染&#xff0c;被一些别有用心的人搞了鬼了&#xff0c; 2还有一个重要原因是不同的DNS服务器解析的速度不一样。 1 建议设置dns地址为114.114.114.114.我觉得假设一个县城如果有一个DNS服务器的话&#xff0c;这个服务器很可能不会存储…

求组合数(递归版)(杨辉三角形)

description 请编写递归函数&#xff0c;求组合数。 函数原型 double Cmb(int x, int y); 说明&#xff1a;x 和 y 为非负整数&#xff0c;且 x≥y&#xff0c;函数值为组合数 C x y ​ 。 裁判程序 #include <stdio.h> double Cmb(int x, int y); int main() { int m…

基于华为云云耀云服务器L实例下的场景体验 | Docker可视化工具Portainer

基于华为云云耀云服务器L实例下的场景体验 | Docker可视化工具Portainer 1. 简介2. 准备工作3. 工具配置3.1. 配置安全组3.2. 初始化配置Portainer 4. 使用Portainer部署MySQL容器4.1. 创建MySQL容器4.2. 连接MySQL容器 1. 简介 随着云计算时代的进一步深入&#xff0c;越来越多…

【计算机网络笔记三】传输层

端口 在网络中如何标记一个进程&#xff1f; TCP/IP 体系的传输层使用【端口号】来标记区分应用层的不同应用进程。这里说的端口是一个逻辑的概念&#xff0c;并不是实实在在的物理端口。 端口号使用 16 比特表示&#xff0c;取值范围是 0 ~ 65535&#xff0c;端口号分为以…

「大数据-2.0」安装Hadoop和部署HDFS集群

目录 一、下载Hadoop安装包 二、安装Hadoop 0. 安装Hadoop前的必要准备 1. 以root用户登录主节点虚拟机 2. 上传Hadoop安装包到主节点 3. 解压缩安装包到/export/server/目录中 4. 构建软链接 三、部署HDFS集群 0. 集群部署规划 1. 进入hadoop安装包内 2 进入etc目录下的hadoop…

分享40个Python源代码总有一个是你想要的

分享40个Python源代码总有一个是你想要的 源码下载链接&#xff1a;https://pan.baidu.com/s/1PNR3_RqVWLPzSBUVAo2rnA?pwd8888 提取码&#xff1a;8888 下面是文件的名字。 dailyfresh-天天生鲜 Django-Quick-Start freenom-自动续期域名的脚本 Full Stack Python简体中…

竟然可以在一个项目中混用 Vue 和 React?

React和Vue是前端开发中的两大热门框架&#xff0c;各自都有着强大的功能和丰富的生态系统。然而&#xff0c;你有没有想过&#xff0c;在一个项目中同时使用React和Vue&#xff1f;是的&#xff0c;你没有听错&#xff0c;可以在同一个项目中混用这两个框架&#xff01;本文就…

redis学习(一)——初识redis

redis学习&#xff08;一&#xff09;——初识redis 非关系型数据库 redis是非关系型数据库&#xff0c;和mysql不同&#xff0c;redis中的所有数据都是以key&#xff1a;value形式存在的 两者区别 SQL | NoSQL 结构化 | 非结构化 关联的 | 无关联 sql查询 | 非sql ACI…

[python 刷题] 22 Generate Parentheses

[python 刷题] 22 Generate Parentheses 题目&#xff1a; Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses. 这里 well-formed 指的就是合法的括号配对&#xff0c;这里会提两个解 第一个是暴力解&#xff0c;也就…

服务注册发现_服务发现Discovery

修改payment8001的Controller /*** 支付控制层*/ Slf4j RestController public class PaymentController {Autowiredprivate DiscoveryClient discoveryClient;GetMapping("/payment/discovery")public Object discovery(){// 获取所有微服务信息List<String>…

栈和队列2——队列的实现

栈和队列2——队列的实现 一&#xff0c;前言二&#xff0c;队列的定义三&#xff0c;队列的结构四&#xff0c;队列的实现4.1队列初始化4.2队列的销毁4.3队列的尾插4.4队列的删除4.5找队头的数据4.6找队尾的数据4.7判断为空4.8计算长度 五&#xff0c;小结 一&#xff0c;前言…