【静态分析】在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.Resource
    private 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);
    }

    @Override
    public 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 analysis
  analysisClass: pascal.taie.analysis.extractapi.TestMethod
  id: 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注入漏洞

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

NFT Insider #131:Mocaverse NFT市值破3.5万ETH,The Sandbox 参加NFCsummit

引言&#xff1a;NFT Insider由NFT收藏组织WHALE Members&#xff08;https://twitter.com/WHALEMembers&#xff09;、BeepCrypto &#xff08;https://twitter.com/beep_crypto&#xff09;联合出品&#xff0c;浓缩每周NFT新闻&#xff0c;为大家带来关于NFT最全面、最新鲜、…

0基础学习Mybatis系列数据库操作框架——Mysql的Geometry数据处理之WKT方案

大纲 几何结构构建点点集合线线集合面面集合几何信息集合 TypeHandlerSQL操作写入操作读取操作完整XML Mapper测试代码建表SQL总结代码参考资料 WKT全称是Well-Known Text。它是一种表达几何信息的字符串内容。比如点可以用WKT表示为POINT (3 3)&#xff1b;线可以用WKT表示为L…

uniapp使用内置的switch组件的问题

说明 开关选择器 属性说明 属性名类型默认值说明平台差异说明checkedBooleanfalse是否选中disabledBooleanfalse是否禁用不支持&#xff1a;抖音小程序、飞书小程序typeStringswitch 样式 有效值&#xff1a;switch、checkbox colorColorswitch的颜色&#xff0c;通css的co…

【Text2SQL 经典模型】X-SQL

论文&#xff1a;X-SQL: reinforce schema representation with context ⭐⭐⭐⭐ Microsoft, arXiv:1908.08113 X-SQL 与 SQLova 类似&#xff0c;使用 BERT style 的 PLM 来获得 representation&#xff0c;只是融合 NL question 和 table schema 的信息的方式不太一样&#…

响应式处理-一篇打尽

纯pc端响应式 pc端平常用到的响应式布局 大致就如下三种&#xff0c;当然也会有其他方法&#xff0c;欢迎评论区补充 将div height、width设置成100% flex布局 flex布局主要是将flex-wrap: wrap&#xff0c; 最后&#xff0c;你可以通过给子元素设置 flex 属性来控制它们的…

基于STM32实现智能风扇控制系统

目录 文章主题环境准备智能风扇控制系统基础代码示例&#xff1a;实现智能风扇控制系统 PWM控制风扇速度温度传感器数据读取串口通信控制应用场景&#xff1a;智能家居与环境调节问题解决方案与优化收尾与总结 1. 文章主题与命名 文章主题 本教程将详细介绍如何在STM32嵌入式…

Docker仅需3步搭建免费私有化的AI搜索引擎-FreeAskInternet!

简介 FreeAskInternet 是一个完全免费、私有且本地运行的搜索引擎&#xff0c;并使用 LLM 生成答案&#xff0c;无需 GPU。用户可以提出问题&#xff0c;系统会进行多引擎搜索&#xff0c;并将搜索结果合并到ChatGPT3.5 LLM中&#xff0c;并根据搜索结果生成答案。 什么是 Fr…

Windows11的这个地方暴露着你的隐私,把它关掉避免尴尬

前言 现在的电脑真的是越来越智能化&#xff01;现在有很多小伙伴都是用着Windows11的吧&#xff01;用习惯了Windows11之后&#xff0c;突然发现它还是挺顺手的。 但不知道你有没有发现&#xff0c;Windows11上面有个地方暴露着你的隐私。这个隐私可能是某个小姐姐的图片&am…

【EasyX】快速入门——消息处理,音频

1.消息处理 我们先看看什么是消息 1.1.获取消息 想要获取消息,就必须学会getmessage函数 1.1.1.getmessage函数 有两个重载版本,它们的作用是一样的 参数filter可以筛选我们需要的消息类型 我们看看参数filter的取值 当然我们可以使用位运算组合这些值 例如,我们…

sequence cache太小导致enq: SQ – contention

当业务卡的时候&#xff0c;发现大量等待事件为enq: SQ – contention&#xff0c;检查awr的top 5事件&#xff1a; sql语句对sequence的调用非常频繁&#xff1a; 对这些语句排查发现sequence cache值均为默认20&#xff0c;调大cache到1000值&#xff1a; SQL> select SE…

sql select获取mysql所有数据库,指定数据库下的所有表名

介绍一下 MySQL 8.0 中默认安装的几个系统数据库/模式。 当我们安装 MySQL 8.0 并初始化数据库之后&#xff0c;默认会创建以下系统数据库&#xff1a; mysql&#xff0c;存储了 MySQL 服务器正常运行所需的各种信息。 information_schema&#xff0c;提供了访问数据库元数据…

HarmonyOS之ArkUI布局设计常见细节

这里写目录标题 1. Button设置带有渐变色的背景图片无效1.1 问题分析1.2 成功案例 2. 路由跳转失败2.1 问题分析 1. Button设置带有渐变色的背景图片无效 1.1 问题分析 说明&#xff1a;设置颜色渐变需先设置backgroundColor为透明色。 Button($r(app.string.login), { type…

海外仓储管理系统:提升效率,标准化海外仓管理,科技赋能业务

海外仓作为跨境物流的关键一环&#xff0c;完全可以说海外仓的效率直接决定了后续物流的整体运作效率。 对于海外仓而言&#xff0c;一套高效&#xff0c;易用的海外仓储系统&#xff0c;无疑将成为提升企业竞争力的重要工具&#xff0c;帮助海外仓实现从野蛮生长到标准化管理…

项目十二:简单的python基础爬虫训练

许久未见&#xff0c;甚是想念&#xff0c;今日好运&#xff0c;为你带好运。ok&#xff0c;废话不多说&#xff0c;希望这门案例能带你直接快速了解并运用。&#x1f381;&#x1f496; 基础流程 第一步&#xff1a;安装需要用到的requests库&#xff0c;命令如下 pip inst…

网络拓扑—DNS服务搭建

文章目录 DNS服务搭建网络拓扑配置网络DNSPC 安装DNS服务配置DNS服务创建正向查找区域创建反向查找区域创建子域名 PC机DNS域名解析 DNS服务搭建 网络拓扑 为了节省我的U盘空间&#xff0c;没有用路由器&#xff0c;所以搭建的环境只要在同网段即可。 //交换机不用考虑 DNS&a…

探数API统计分享-1949年-2021年中国历年夏粮产量统计报告

​​​​​​​​中国历年夏粮产量​&#xff0c;为1949年到2021年我国每年的夏粮产量数据。2021年&#xff0c;我国夏粮产量为14596万吨&#xff0c;比上年增长2.2%。 数据统计单位为&#xff1a;万吨 。 我国夏粮产量有多少&#xff1f; 2021年&#xff0c;我国夏粮产量为1…

计算机网络安全控制技术

1.防火墙技术 防火墙技术是近年来维护网络安全最重要的手段&#xff0c;但是防火墙不是万能的&#xff0c;需要配合其他安全措施来协同 2.加密技术 目前加密技术主要有两大类&#xff1a;对称加密和非对称加密 3.用户识别技术 核心是识别网络者是否是属于系统的合法用户 …

2024.5.26 机器学习周报

目录 引言 Abstract 文献阅读 1、题目 2、引言 3、创新点 4、Motivation 5、naive Lite-HRNet 6、Lite-HRNet 7、实验 深度学习 解读SAM(Segment Anything Model) 1、SAM Task 2、SAM Model 2.1、Patch Embedding 2.2、Positiona Embedding 2.3、Transformer …

VERY DEEP CONVOLUTIONAL NETWORKS FOR LARGE-SCALE IMAGE RECOGNITION--论文笔记

论文笔记 论文来源 Very Deep Convolutional Networks for Large-Scale Image Recognition 代码来源 还没上传 数据集 这里采用的是猫狗数据集 还没上传 1论文摘要的翻译 在这项工作中&#xff0c;我们研究了卷积网络深度对其在大规模图像识别设置中的准确性的影响。我…

Offline RL : Beyond Reward: Offline Preference-guided Policy Optimization

ICML 2023 paper code preference based offline RL&#xff0c;基于HIM&#xff0c;不依靠额外学习奖励函数 Intro 本研究聚焦于离线偏好引导的强化学习&#xff08;Offline Preference-based Reinforcement Learning, PbRL&#xff09;&#xff0c;这是传统强化学习&#x…