长亭百川云 - 文章详情

线程注入与JRASP实践

RASP安全技术

73

2024-07-13

    任意代码执行漏洞中,攻击者通过开启一个新的线程来执行命令时,rasp丢失请求的上下文、执行堆栈等重要参数,导致检测算法(堆栈算法、请求参数特征等无法关联)失效,极大的影响RASP的防御功能与溯源能力。  
  

01 案例  

    如下案例:http 请求线程执行到下面的代码时,新建一个新的线程来执行任意,命令,http特征参数丢失。


`<%@ page language="java" contentType="text/html; charset=UTF-8"`    `pageEncoding="UTF-8"%>`    `<%@ page import="java.io.IOException" %>``DOCTYPE html>``<html>``<head>``<meta charset="UTF-8">``<title>Insert title heretitle>``head>``<body>``<%`    `// 创建线程执行命令,而不是直接执行命令`    `Thread t = new Thread(new Runnable() {`            `@Override``             public void run() {              ``              try {`                `Runtime.getRuntime().exec(new String[]{"touch","/tmp/test"});``              } catch (IOException e) {`                 `e.printStackTrace();`              `}`            `}`    `});`    `t.start();`    `out.println(">==test==<");``%>``body>``html>`
    RASP最终截获的参数会丢失http,无法溯源。(实现原理上的缺陷)  

  

  

**02 参数丢失原因与优化措施**

  

    rasp 中使用 ThreadLocal 在线程的不同hook点处传递http等参数,由于无法跨线程,参数必然丢失。  
    有更好的线程关联类,来解决上面新建线程参数丢失问题:java.lang.InheritableThreadLocal类。  

Inheritable thread-local variables are used in preference to ordinary thread-local variables when the per-thread-attribute being maintained in the variable (e.g., User ID, Transaction ID) must be automatically transmitted to any child threads that are created.

    实现原理:在父线程创建子线程时,向子线程传递变量。可以参考:\[InheritableThreadLocal\](https://www.jianshu.com/p/94ba4a918ff5)。  
  
**03 JRASP实现**  

  

*   使用InheritableThreadLocal创建线程变量
    


`// 线程上下文`                                                                                              `// 上下文增强:使用 InheritableThreadLocal 代替 ThreadLocal 防止线程注入`                                              `public static InheritableThreadLocal<Context> requestContext = new InheritableThreadLocal<Context>() {`    `@Override``     protected Context initialValue() {                                                                 ``         return new Context();                                                                          ``}`                                                                                                 `};` ` // 模块中使用线程上下文` `@RaspResource` `private ThreadLocal<Context> context;`


*   线程变量的清除  
    

  

    由于jrasp的基本特征是热卸载(加载),如果不能清除线程变量,将会导致已经加载的 jrasp-agent/module 无法正常卸载,造成比较严重的内存泄漏。  
    因此,jrasp-agent 在卸载时, 执行**强制清除**线程变量操作,彻底解决内存泄漏问题;  

// 除去 context 线程变量`` List<Thread> threadList = ThreadUtil.getThreadList(); `` for (Thread thread : threadList) { `` /** `` * 在 rasp 退出时清理线程变量,这里使用 inheritableThreadLocals 应该清除 inheritableThreadLocals `` * @see Thread.inheritableThreadLocals `` * @see Thread.threadLocals ``*/      Object threadLocalMap = RaspReflectUtils.unCaughtGetClassDeclaredJavaFieldValue(Thread.class, "inheritableThreadLocals", thread);       if (null != threadLocalMap) {`` // 反射获取 ThreadLocalMap类的 remove 方法 `` Method method = RaspReflectUtils.unCaughtGetClassDeclaredJavaMethod(threadLocalMap.getClass(), "remove", ThreadLocal.class); ``try {              RaspReflectUtils.unCaughtInvokeMethod(method, threadLocalMap, requestContext);                                                  } catch (Exception e) {`` e.printStackTrace(); `` } `` } ``}


  
  
**04 优化后演示**

    在springboot项目中创建一个controller:

`@GetMapping("/get/cmd.do")`    `public void getProcessBuilder(String cmd) throws Exception {`        `Thread thread = new Thread(new Runnable() {`            `@Override`            `public void run() {`                `try {`                    `// 执行命令`                    `execCMD(cmd);`                `} catch (Exception e) {`                    `e.printStackTrace();`                `}`            `}`        `});`        `thread.start();`        `return;`    `}`

 发起请求,检测结果,http 参数未丢失。

  
 卸载jrasp后,触发full gc,可以看到jvm的类卸载事件,完全卸载。

// 卸载jrasp``./attach -p <pid> -s


  

  

》》》1.1.0 新版本功能预览,欢迎申请试用
`### 1.1.0【2022-10】(当前开发版本)``#### Enhancement``+ [attach] 新增jrasp-attach工程(Golang),支持手动注入、查看hook类、更新模块参数和卸载RASP``+ [agent] agent依赖的bridge打包时指定,防止加载错误依赖``+ [agent] 去掉logback/sl4j,使用原生jul ,减少不安全的依赖``+ [agent] 去掉内置jetty,使用原生socket``+ [agent] 使用InheritableThreadLocal代替ThreadLocal防止线程注入``+ [agent] 去掉java-agent的json日志格式,并修改filebeat的日志分割grok表达式``+ [module] 上下文对象优化为context对象``+ [module] module统一参数更新接口``+ [project] 将jrasp-agent、jrasp-module、jrasp-attach和jrasp-daemon等工程合并,统一编译打包``+ [project] 全面兼容 windows、linux、mac``#### BugFix``+ [agent] jar包文件名称增加版本号,解决jar包文件句柄清除问题``+ [module] 替换 @Resource 注解,解决与javax包类的冲突``+ [agent] 解决jvm-sandbox抛出异常时的内存泄漏 bug (jvm-sandbox 已经合入补丁)``+ [jetty module] 解决 http input.read方法重复hook问题 (在openrasp上已经复现该问题)``+ [xxe module] 解决dom4j方法重复hook问题 (在openrasp官方已经确认该问题)``   ``#### TODO``+ [agent] 优化类匹配机制,全局唯一transform实例,减少stw时间``   ``### 1.0.8 【2022-08】(内部测试版本)``#### Enhancement``+ [module] 增加多个安全模块``+ [daemon] 进程扫描优化``+ [daemon] 防止启动多个守护进程``   ``### 1.0.7 【2022-07】(用户使用的稳定版本)``#### Enhancement``+ [daemon] 上报配置更新时间``+ [daemon] daemon启动上报nacos初始化的状态和注册的服务ip``+ [daemon] 发现无法连接nacos时,自动重启,24小时检测一次``   ``#### BugFix``+ [daemon] 修复软刷新panic``+ [daemon] 删除获取依赖的功能,由安全插件自行上报``   ``### 1.0.6 【2022-06】``#### BugFix``+ [daemon] 使用 os.RemoveAll 删除Java进程文件夹``   ``### 1.0.5 【2022-05】``+ [daemon]插件以配置文件为准,配置文件中没有的,删除磁盘上的``+ [daemon]注入后增加软刷新功能和参数更新功能``   ``### 1.0.4 【2022-04】 (开源版本)``+ [agent] 增加native方法hook``+ [daemon] 支持对多个Java进程注入,每个Java进程独立的数据目录`

相关推荐
关注或联系我们
添加百川云公众号,移动管理云安全产品
咨询热线:
4000-327-707
百川公众号
百川公众号
百川云客服
百川云客服

Copyright ©2024 北京长亭科技有限公司
icon
京ICP备 2024055124号-2