【静态分析】在springboot使用太阿(Tai-e)03

参考:使用太阿(Tai-e)进行静态代码安全分析(spring-boot篇三) - 先知社区

1. JavaApi 提取

1.1 分析

预期是提取controller提供的对外API,例如下图中的/sqli/jdbc/vuln

先看一下如何用tai-e去获取router,tai-e的框架工作原理是由Java source code->Soot Jimple IR-> Tai-e IR
后续的pinter anlaysis、taint analysis 都是基于Tai-e IR开展的。
如下是tai-e IR的形式。我们可以根据IR里的注解进行拼接 获取router。

@org.springframework.web.bind.annotation.RestController
@org.springframework.web.bind.annotation.RequestMapping({"/sqli"})
public class org.joychou.controller.SQLI extends java.lang.Object {private static final org.slf4j.Logger logger;private static final java.lang.String driver;@org.springframework.beans.factory.annotation.Value("${spring.datasource.url}")private java.lang.String url;@org.springframework.beans.factory.annotation.Value("${spring.datasource.username}")private java.lang.String user;@org.springframework.beans.factory.annotation.Value("${spring.datasource.password}")private java.lang.String password;@javax.annotation.Resourceprivate org.joychou.mapper.UserMapper userMapper;public void <init>() {[0@L26] invokespecial %this.<java.lang.Object: void <init>()>();[1@L26] return;}@org.springframework.web.bind.annotation.RequestMapping({"/jdbc/vuln"})public java.lang.String jdbc_sqli_vul(@org.springframework.web.bind.annotation.RequestParam("username") java.lang.String username) {java.lang.StringBuilder $r0, $r7, $r8, $r10, $r11;

如果要自己看Tai-e IR的形式,可以在配置里边加入ir-dumper: ;

执行后可以在output/tir看具体的结果

1.2 Tai-e 开发一个新的程序分析

由于我们需要的实现不需要依赖指针分析,所以我们开发插件就没必要用指针分析的插件模式。tai-e给我们提供了开发新的程序分析的扩展方式。How to Develop A New Analysis on Tai-e?
tai-e 提供给我们3中扩展模式:

  • MethodAnalysis 需要实现analyze(IR)方法,这里的输入的IR是每一个method
  • ClassAnalysis 需要实现analyze(Jclass)方法,这里的输入的IR是每一个Class
  • ProgramAnalysis 需要实现analyze()方法,因为这里是整个程序的分析,没有参数传入,如果想获取信息可以用World方法

例子

如果要实现一个自己的Analysis应该如何做?
下边拿一个实现MethodAnalysis的例子来讲。
首先需要继承 MethodAnalysis类,并重载analyze方法。
首先我们需要定义 一个属于自己的ID,比如testmethodanalysis
然后在analyze里定义要分析的内容,比如现在的代码就是打印所有methodName

package pascal.taie.analysis.extractapi;import pascal.taie.analysis.MethodAnalysis;
import pascal.taie.config.AnalysisConfig;
import pascal.taie.ir.IR;public class TestMethod extends MethodAnalysis {public  static final String ID = "testmethodanalysis";public TestMethod(AnalysisConfig config) {super(config);}@Overridepublic Object analyze(IR ir) {//。。。需要分析的内容System.out.println(ir.getMethod().getName());return null;}
}

写完后我们如何让程序运行我们的analyze呢?
找到 resource/tai-e-analyses.yml 加入我们自定义的analysis

  • description:描述是做什么的
  • analysisClass:指定我们编写的类
  • id:对应我们在类里边写的ID,在程序调用时使用
- description: test method analysisanalysisClass: pascal.taie.analysis.extractapi.TestMethodid: testmethodanalysis

我们加入到资源文件后,需要在程序启动时指定我们的分析有两种方式

  • 直接在执行加入参数:-a testmethodanalysis
  • 在配置文件options.yml analyses:添加 testmethodanalysis: ;
  • 运行查看结果

1.3 获取 Api

通过上边的分析我们可以选择ProgramAnalysis的形式来进行分析,因为我们这个分析需要用到classmethod两部分。

1.3.1 POJO

我们先定义了2个类来存储路由信息,未来也可以加上parameters信息。下边是定义的2个类。
MethodRouter 用来存储method的path,可以拓展存储parameters。

public record MethodRouter(String methodName,String path) {}

由于class和method 是1:N的关系,所以我们构建如下对象,来映射class和method关系

public record Router(String className,String classPath,List<MethodRouter> methodRouters){}

1.3.2 提取api程序分析

由于controller的注解一般都是Mapping的形式,我们可以自定义程序获取有Mapping注解的类。

获取所有应用类

因为是对整个program进行分析的,所以我们需要用World来获取所有应用类

World.get().getClassHierarchy().applicationClasses()
获取含有Mapping注解的Method及Path

获取到Method的Path并存储到MethodRouter对象里

jClass.getDeclaredMethods().forEach(jMethod -> {//判断method是否有Mapping注解if (!jMethod.getAnnotations().stream().filter(annotation -> annotation.getType().matches("org.springframework.web.bind.annotation.\\w+Mapping")).toList().isEmpty()) {flag.set(true);//获取method的注解内容并添加进methodRouter类MethodRouter methodRouter = new MethodRouter(jMethod.getName(), formatMappedPath(getPathFromAnnotation(jMethod.getAnnotations())));methodRouters.add(methodRouter);}});

注意:tai-e给出的注解需要我们进行一些处理才能获取到注解里的path,下边是代码片段

public String getPathFromAnnotation(Collection<Annotation> annotations) {ArrayList<String> path = new ArrayList<>();annotations.stream().filter(annotation -> annotation.getType().matches("org.springframework.web.bind.annotation.\\w+Mapping")).forEach(annotation -> path.add(Objects.requireNonNull(annotation.getElement("value")).toString()));return path.size() == 1 ? path.get(0) : null;}
组建Router对象

通过上边获取到的method path list 和 class 来组建router对象。

Router router = new Router(jClass.getName(), formatMappedPath(getPathFromAnnotation(jClass.getAnnotations())),methodRouters);
routers.add(router);

1.4 结果展示

具体食用方法

下载代码,并移动至spring-boot-3目录下

git clone https://github.com/lcark/Tai-e-demo
cd Tai-e-demo/spring-boot-3
git submodule update --init

2. 将java-sec-code文件夹移至与Tai-e-demo文件夹相同目录下

3. 将pojoExtractApi文件放到src/main/java/pascal.taie/analysis/extractapi 下

4. 添加我们的analysis程序到tai-e main/resources/tai-e-analyses.yml下

5. 构建fatjar包

6. 使用如下命令运行tai-e便可以成功获取到扫描结果
java -cp D:\work\Tai-e\Tai-e\Tai-e\build\tai-e-all-0.5.1-SNAPSHOT.jar pascal.taie.Main --options-file=options.yml

如下图所示,成功获取所有api

2. 添加 Mybatis Sink点

2.2 Mybatis介绍

MyBatis 是一款优秀的持久层框架/半自动的对象关系映射,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过 XML注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
可以看下边的两种形式的例子.

2.2.1 XML形式

2.2.2 注解形式

通过上边的例子我们可以看出 mybatis 执行的sql语句插入的参数有两种形式

#{parameterName}: #使用预编译,通过 PreparedStatement 和占位符来实现,会把参数部分用一个占位符 ? 替代,而后注入的参数将不会再进行 SQL 编译,而是当作字符串处理。可以避免 SQL 注入漏洞
${parameterName} :$表示使用拼接字符串,将接受到参数的内容不加任何修饰符拼接在 SQL 中。易导致 SQL 注入漏洞
虽然#可以预防SQL注入,但是在处理orderby、like、in等语句的情况会报错需要特殊处理。

2.3 注解形式分析

由于mybatis的形式是#{}和${}的形式进行参数拼接,这也就导致我们没办法直接将某个函数的parameter当作sink点来检查SQLI,所以需要我们进行判断是否该函数的parameter传入了执行sql语句中是用$进行拼接的,然后加入sink点。
也就是如下代码中的username。

@Select("select * from users where username = '${username}'")
List<User> findByUserNameVuln01(@Param("username") String username);

2.3.1 代码实现

总结下来就是如下的步骤:
1.筛选出存在Mapper(org.apache.ibatis.annotations.Mapper)注解的类

List<JClass> list =  World.get().getClassHierarchy().applicationClasses().toList();
for (JClass jClass : list) {if (!jClass.getAnnotations().stream().filter(annotation -> annotation.getType().matches("org.apache.ibatis.annotations.Mapper")).toList().isEmpty()}

2.筛选出有Select注解的method(order 、in等暂时没处理).

jClass.getDeclaredMethods().forEach(jMethod -> {if (!jMethod.getAnnotations().stream().filter(annotation -> annotation.getType().matches("org.apache.ibatis.annotations.Select")).toList().isEmpty()){}

3.对$进行正则匹配筛选,匹配出里边的内容(username)

String valueFromAnnotation = getValueFromAnnotation(jMethod.getAnnotations());
if (valueFromAnnotation!=null){if (valueFromAnnotation.contains("$")){//                                System.out.println(jMethod);Pattern pattern = Pattern.compile("\\$\\{([^}]+)\\}");Matcher matcher = pattern.matcher(valueFromAnnotation);

由于需要从注解里获取value ,我们写了一个method从annotations获取value

public static String getValueFromAnnotation(Collection<Annotation> annotations) {ArrayList<String> value = new ArrayList<>();annotations.stream().filter(annotation -> annotation.getType().matches("org.apache.ibatis.annotations..*")).forEach(annotation -> value.add(Objects.requireNonNull(annotation.getElement("value")).toString()));return value.size() == 1 ? value.get(0) : null;
}

4.对method的参数进行处理,找到名字和$里的内容一致的参数,组装成为sink点,然后存储进入一个List。

while (matcher.find()) {String sink = matcher.group(1);int paramCount = jMethod.getParamCount();for (int i = 0 ; i< paramCount;i++){String paramValue = getValueFromAnnotation(jMethod.getParamAnnotations(i));if (paramValue.contains(sink)){Sink sink1 = new Sink(jMethod, new IndexRef(IndexRef.Kind.VAR, i,null));sinkList.add(sink1);}}
}

5.在程序加载config sink点后加入我们的mybatis sink点。
这里我们创建了一个静态方法来返回我们找到的sink点。然后就需要加入到程序的sinks中。
这里可以在java/pascal/taie/analysis/pta/plugin/taint/TaintConfig.java加载config后 加入进去,至于为什么加在这里,可以看下边Taint-config 加载流程

Taint-config加载流程

由于我们需要将sink点加入sink list 中。但是我们在 sinkhandler处没办法直接加入list内,由于该字段是final类型。

尝试删除final,发现该类是UnmodifiableCollection 看名字顾名思义是不可以修改的类,所以会报错。

为此我们需要分析tai-e加载sink的流程,找到合适的加入sink点的位置。

1.在TaintAnalysis setSolver 函数内会用TaintConfig来加载taint-config 文件。

2.利用jackson 自定义反序列化 读取taintconfig文件

3.查看自定义 Deserializer 类,我们可以看到会deserializerSinks会把config里的sinks获取出来

4.我们可以看到deserializerSinks在加载sinks后会将list为不可修改,所以我们在返回前添加我们的sink点。

2.4 XML形式分析

xml形式比上述流程就是多了一个步骤,就是用id寻找method的步骤。如下图,所以此处就不多赘述了。

2.5 结果展示

具体食用方法
1. 下载代码,并移动至spring-boot-3目录下

git clone https://github.com/lcark/Tai-e-demo
cd Tai-e-demo/spring-boot-3
git submodule update --init

2. 将java-sec-code文件夹移至与Tai-e-demo文件夹相同目录下

3. 将AddMybatisSinkHandler移动到java/pascal/taie/analysis/pta/plugin/taint文件下
在TaintConfig.java里deserializeSinks加入如下位置加入代码

List<Sink> mybatisSinks = AddMybatisSinkHandler.AddMybatisSink();sinks.addAll(mybatisSinks);

4. 构建fatjar包

5. 使用如下命令运行tai-e便可以成功获取到扫描结果
java -cp D:\work\Tai-e\Tai-e\Tai-e\build\tai-e-all-0.5.1-SNAPSHOT.jar pascal.taie.Main --options-file=options.yml

成功检测mybatis的sqli注入漏洞

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

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

相关文章

浅谈分布式系统

目录 一、单机架构二、分布式架构1、应用服务与数据库分离2、负载均衡3、数据库读写分离4、引入缓存5、数据库分库分表6、引入微服务 一、单机架构 单机架构&#xff0c;只有一台服务器&#xff0c;这个服务器负责所有工作。 绝大多数公司的产品&#xff0c;都是这种单机架构。…

[论文笔记]REACT: SYNERGIZING REASONING AND ACTING IN LANGUAGE MODELS

引言 今天带来一篇经典论文REACT: SYNERGIZING REASONING AND ACTING IN LANGUAGE MODELS的阅读笔记&#xff0c;论文中文意思是 在语言模型中协同推理和行动。 虽然大型语言模型(LLMs)在语言理解和互动决策任务中展现出强大的能力&#xff0c;但它们在推理(例如思维链提示)和…

Rust 中 Mutex 的用法

在 Rust 中&#xff0c;Mutex&#xff08;互斥锁&#xff09;是用于同步并发访问共享资源的机制。Rust 标准库中的 Mutex 结构体位于 std::sync::Mutex 中&#xff0c;它提供了线程安全的数据访问。Mutex 保证了在同一时间只有一个线程可以访问被锁定的数据。 以下是 Mutex 的…

画图工具之PlantUML插件使用

文章目录 1 PlantUML插件1.1 引言1.2 什么是PlantUML1.3 PlantUML插件1.3.1 IntelliJ IDEA中插件1.3.2 VS Code中插件1.3.3 使用例子 1.4 PlantUML时序图语法1.4.1 声明参与者1.4.2 消息传递1.4.2.1 同步消息1.4.2.2 异步消息1.4.2.3 返回消息1.4.2.4 自调用 1.4.3 生命线&…

比特米盒2代刷入ARMBIAN

概述 因为最近在整家庭NAS&#xff0c;类似魔百盒之类的机顶盒无法内置硬盘&#xff0c;所以将目光盯上了比特米盒、私家云以及和逸云&#xff0c;海鲜市场一番对比下来也就比特米盒&#xff08;CM2-B&#xff09;的性价比最高&#xff0c;而且还支持双盘位&#xff0c;所以采…

【大模型】fineturn Q-wen

github上下载qwen1_5源码 修改finetun.sh 然后在路径qwen1_5/examples/sft下修改finetun.sh, 内容如下 #!/bin/bash export CUDA_DEVICE_MAX_CONNECTIONS1 DIRpwd# Guide: # This script supports distributed training on multi-gpu workers (as well as single-worker trai…

批处理--将指定磁盘根目录所有隐藏的文件(包括文件夹)去除隐藏属性

如下是实现的脚本&#xff1a;-------------------------------------------------- :loopcd / set /p driverName"请输入驱动器盘符&#xff08;例如&#xff1a;C或c&#xff09;&#xff1a;"%driverName%: dir /AH %driverName%: pausefor /f "delims"…

Leetcode刷题2

文章目录 前言寻找两个正序数组的中位数1️⃣ 双指针快速排序2️⃣ 第k小数解法 Z 字形变换1️⃣ 个人解法2️⃣巧妙解法13️⃣巧妙解法2 字符串转换整数 (atoi)1️⃣ 常规方法2️⃣ 作弊方法&#x1f62b; 整数转罗马数字1️⃣ 常规方法&#xff1a;按照给定规则写出判断条件即…

前端面试题日常练-day32 【面试题】

题目 希望这些选择题能够帮助您进行前端面试的准备&#xff0c;答案在文末。 1. 在jQuery中&#xff0c;以下哪个选项用于获取元素的文本内容&#xff1f; a) text() b) html() c) val() d) attr() 2. jQuery中&#xff0c;以下哪个选项用于在元素上添加一个自定义数据属性…

感动心灵的声音——带情绪的AI配音技术在影视和广告领域的应用

近年来&#xff0c;随着人工智能技术的飞速发展&#xff0c;带情绪的AI配音技术作为其中一项重要应用&#xff0c;正逐渐在影视和广告行业展现其独特的魅力和应用价值。传统的配音工作不仅需要具备优秀的嗓音和表演能力&#xff0c;还要求配音演员能够准确捕捉并表达角色的情感…

WSL调用docker

WSL&#xff08;windows subsystem linux&#xff09;是window系统的原生linux子系统&#xff0c;用于代码开发很方便。 希望在wsl里面运行docker&#xff0c;首先要安装docker在WSL中使用&#xff0c;大部分人的第一想法肯定是用以下命令行安装&#xff08;个人不推荐&#x…

java的unsafe

在Java中&#xff0c;sun.misc.Unsafe 是一个强大且危险的类&#xff0c;它提供了一些直接操作内存、对象和线程的底层功能。这个类通常不鼓励普通开发者使用&#xff0c;因为它绕过了Java语言的一些安全性和内存管理机制&#xff0c;可能会导致难以追踪的错误和安全漏洞。 Un…

前端生成二维码

直接img标签显示 npm i use_qrcode npm包地址 <img :src"qrcode" alt"QR Code" /> const txt: any ref(https://baidu.com) const qrcode useQRCode(txt) const qrcodeLogo useQRCode(txt, { logoSrc: https://www.antdv.com/assets/logo.1ef800…

2.go环境配置与开发工具选择

go 环境配置 下载安装包 官网(https://go.dev/dl/) 下载地址(国内)(https://golang.google.cn/dl/) 根据自己的操作系统选择下载即可 下载后安装 记住地址 比如&#xff1a; D:\work\devtool\go 配置系统环境变量 PATH 指向 go 的安装 bin 目录 比如&#xff1a; D:\work…

若依前端vue实现 输入框下拉选择加搜索用户

探索代码以及详细的注解 <template><div><el-select v-model"selectedUserId" filterable placeholder"选择用户" change"handleChange"><el-optionv-for"user in filteredUsers":key"user.userId":l…

集合框框框地架

这一次来介绍一下常用的集合&#xff1a; 首先是两种集合的《家庭系谱图》&#xff1a; 接下来介绍一下集合的种类&#xff1a; Collection Set SetTreeSet&#xff1a;基于红⿊树实现&#xff0c;⽀持有序性操作&#xff0c;例如&#xff1a;根据⼀个范围查找元素的操作。但…

如何使用纯原生的ADO.NET技术进行数据读取

目录 1. 引用命名空间 2. 创建连接字符串 3. 打开数据库连接 4. 执行SQL查询 5. 读取结果集 6. 处理异常和关闭连接 1. 引用命名空间 在代码文件中引用几个关键的System.Data.SqlClient命名空间&#xff0c;这些命名空间包含了用于数据库操作的类。 using System.Data.Sq…

Unity实现TableView

基于Scrollview封装的TableView&#xff0c;实现对视野外的Cell回收利用&#xff0c;减少创建Cell的开销。 核心逻辑如下&#xff1a; /***************************************动态使用cell核心逻辑开始 **************************************///计算所有cell的坐标信息 …

利用java8 的 CompletableFuture 优化 Flink 程序,性能提升 50%

你好&#xff0c;我是 shengjk1&#xff0c;多年大厂经验&#xff0c;努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注&#xff01;你会有如下收益&#xff1a; 了解大厂经验拥有和大厂相匹配的技术等 希望看什么&#xff0c;评论或者私信告诉我&#xff01; 文章目录 一…

flume sink 简介及官方用例

1、HDFS Sink 此sink将事件写入 Hadoop 分布式文件系统 &#xff08;HDFS&#xff09; 中。它目前支持创建文本和序列文件。它支持两种文件类型的压缩。可以根据经过的时间或数据大小或事件数定期滚动文件&#xff08;关闭当前文件并创建一个新文件&#xff09;。它还按事件起…