【靜態分析】在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.pswp.cn/diannao/14592.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/14592.shtml
英文地址,請注明出處:http://en.pswp.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;。它還按事件起…