【靜態分析】在springboot使用太阿(Tai-e)01

參考:使用太阿(Tai-e)進行靜態代碼安全分析(spring-boot篇一) - 先知社區

----------------------------------------------------------------------

?由于spring-boot實現了控制反轉與面向切面編程的設計思想,使得程序并非順序執行,因此很難通過程序入口來順序分析所有代碼。本篇文章旨在從0開始,利用Tai-e來分析spring-boot程序,解決控制反轉的問題。

1. 從0開始配置tai-e并加載java-sec-code

1.1 下載tai-e代碼

創建文件夾并進入

git clone https://github.com/pascal-lab/Tai-e.git

git init

git submodule update --init --recursive

1.2 IDEA配置tai-e

其實就是按照官方文檔進行配置IDEA
在打開tai-e程序后等待一會

Tai-e加載完之后

設置

File->Project Structure,將SDK與Language level設置為17

File->Settings

然后將Build and run using與Run tests using改為idea

1.3 編譯java-sec-code

下載java-sec-code源碼

git clone https://github.com/JoyChou93/java-sec-code.git

cd java-sec-code

mvn clean package -X

注意:若出現'mvn'不是內部或外部命令,也不是可運行的程序或批處理文件。

則首先確認自己是否安裝了maven

若已經安裝,則

  • 添加Maven到環境變量

    • 打開系統的環境變量設置,找到Path變量,確保Maven的bin目錄路徑已經添加到Path變量中。
  • 重新打開命令行執行

等待

看到Build success代表編譯成功

1.4 配置tai-e加載java-sec-code

首先創建common目錄和options和taint-config文件。作為我們自己的配置

options文件內容,注意需要修改appClassPath也就是我們剛才編譯的java-sec-code的target。

optionsFile: null
printHelp: false
classPath: []
appClassPath:- D:\software\java-sec-code\java-sec-code\target\classes
mainClass:
inputClasses: []
javaVersion: 8
prependJVM: false
allowPhantom: true
worldBuilderClass: pascal.taie.frontend.soot.SootWorldBuilder
outputDir: output
preBuildIR: false
worldCacheMode: true
scope: REACHABLE
nativeModel: true
planFile: null
analyses:#  ir-dumper: ;pta: cs:ci;implicit-entries:true;distinguish-string-constants:null;reflection-inference:solar;merge-string-objects:false;merge-string-builders:false;merge-exception-objects:false;taint-config:config/common/taint-config.yml;
onlyGenPlan: false
keepResult:- $KEEP-ALL

taint-config文件內容,這個文件暫時不需要修改,就是加了一個sources和sinks點以及transfers。

sources:
#  - { kind: param, method: "<org.joychou.controller.SQLI: java.lang.String jdbc_sqli_sec(java.lang.String)>", index: 0}- { kind: param, method: "<org.joychou.controller.SQLI: java.lang.String jdbc_sqli_vul(java.lang.String)>", index: 0}
#  - { kind: param, method: "<org.joychou.controller.SpEL: void main(java.lang.String[])>", index: 0}
#  - {kind: param, method: "<org.joychou.controller.Rce: java.lang.String CommandExec(java.lang.String)>",index: 0}
sinks:## SQLI- { vuln: "SQL Injection", level: 4, method: "<java.sql.Statement: java.sql.ResultSet executeQuery(java.lang.String)>", index: 0 }- { vuln: "SQL Injection", level: 4, method: "<java.sql.Connection: java.sql.PreparedStatement prepareStatement(java.lang.String)>", index: 0 }
transfers:- { method: "<java.lang.String: java.lang.String concat(java.lang.String)>", from: base, to: result }- { method: "<java.lang.String: java.lang.String concat(java.lang.String)>", from: 0, to: result }- { method: "<java.lang.String: char[] toCharArray()>", from: base, to: result }- { method: "<java.lang.String: void <init>(char[])>", from: 0, to: base }- { method: "<java.lang.String: void getChars(int,int,char[],int)>", from: base, to: 2 }- { method: "<java.lang.String: java.lang.String format(java.lang.String,java.lang.Object[])>", from: "1[*]", to: result }- { method: "<java.lang.StringBuffer: void <init>(java.lang.String)>", from: 0, to: base }- { method: "<java.lang.StringBuffer: java.lang.StringBuffer append(java.lang.String)>", from: 0, to: base }- { method: "<java.lang.StringBuffer: java.lang.StringBuffer append(java.lang.String)>", from: 0, to: result }- { method: "<java.lang.StringBuffer: java.lang.StringBuffer append(java.lang.String)>", from: base, to: result }- { method: "<java.lang.StringBuffer: java.lang.String toString()>", from: base, to: result }- { method: "<java.lang.StringBuilder: void <init>(java.lang.String)>", from: 0, to: base }- { method: "<java.lang.StringBuilder: java.lang.StringBuilder append(java.lang.String)>", from: 0, to: base }- { method: "<java.lang.StringBuilder: java.lang.StringBuilder append(java.lang.String)>", from: 0, to: result }- { method: "<java.lang.StringBuilder: java.lang.StringBuilder append(java.lang.String)>", from: base, to: result }- { method: "<java.lang.StringBuilder: java.lang.String toString()>", from: base, to: result }call-site-mode: true

配置Main函數參數

現在可以運行了,但是你會發現沒有taint-flow的結果。
主要的問題是tai-e的taint-analysis是基于pointer-anysis的。而pointer-analysis的分析是基于worklist,這個worklist如果是java se程序初始化就是main函數,可以通過main函數進行分析,進行函數調用處理,從而reach到需要分析的函數。由于我們的是springboot程序包含依賴注入和控制反轉等,所以從springboot的入口tai-e沒辦法分析到我們的controller函數,所以pointer-anlaysis的結果也就是空的,導致taint-anlaysis結果也是空的。

經過分析發現tai-e分析SpringBoot項目存在2個問題。
1. 缺少entrypoint,因為pointerAnalysis分析沒辦法reach到我們需要分析的controller方法。
2. 缺少source,我們暫時沒有辦法通過yml將所有Mapping注解的parameters加入sources,我們上邊yml僅加入了一個source。
需要解決以上兩個問題,才能進行基礎的分析。

2. 關鍵源碼分析及實現

2.1 PointerAnaysis分析及入口點添加

由于tai-e的插件是集成在PointerAnalysis,包括污點分析也是,也就是說PointerAnalysis就是這些分析的核心。所以在寫如何編寫插件前我們先大概分析一下PointerAnlaysis的執行流程。

2.1.1 PointerAnaysis執行流程

我們先看PointerAnalysisrunAnalysis方法,這個其實不算是入口點,analyze才是,但是analyze僅根據配置然后調用runAnalysis,所以我們直接分析這個就好。

DefalutSolver實現指針分析以及插件的調用,并返回指針分析的結果(core)。

Plugin即一個插件,可以通過編寫插件的方式,在進行指針分析的過程中執行我們想要的操作(污點分析也是類似的操作)。

接下來看一下setPlugin方法,目前先不用修改它。

接下來分析DefaultSolver的solve方法。

solve方法會首先調用 initialize 方法,然后執行analyze()方法

initialize方法:
● 初始化調用圖、指針流向圖 、worklist(可以理解為指針分析的工作集)、reachableMethods(也就是分析能到達的方法)、initializedClasses(可以理解為內置的類,會進行指針分析,不需要我們添加)、stmtProcessor(這個類是指針分析處理語句的核心,根據訪問者模式處理對行的語句(new、load、invoke、array等))
● 然后會執行插件的onStart()方法

analyze方法

  • 通過消費worklist中的Entry,對Entry進行指針分析的處理,然后調用Plugin的onNewPointsToSet方法(本篇文章用不到該方法,該方法在處理field和array source時會用到)
  • 在處理worklist后調用Plugin.onFinish()方法

2.1.2 分析EntryPointerHandler

通過對PointerAnalysis執行流程的分析應該能大概了解Plugin的執行順序了。
看一下Plugin的interface ,有一系列plugin的方法。

  • 插件方法執行流程
    loadPlugin(pointerAnalysis加載插件)->setSolver->onStart->指針分析以及一些plugin方法->onFinish
  • 從上邊我們可以理解編寫Plugin的流程,選擇我們需要的方法比如onStart 、onFinish
  • 在PointerAnalysis加入編寫的插件。

看一下tai-e自帶的EntryPointHandler它就是在onStart處判斷加入口點。

2.1.3 添加EntryPoint

這樣加入我們自己入口點的方法也有了,在onStart的時候把所有 有Mapping注解的方法都加入 入口點,這樣pointeranalysis就能分析到我們的source點了,taintanalysis也會有結果。
下邊的代碼就是獲取所有的class,然后獲取class的method,若注解是
Mapping,則加入entrypoint

public class AddControllerEntryPointHandler implements Plugin {private  Solver solver;@Overridepublic void setSolver(Solver solver) {this.solver=solver;}@Overridepublic void onStart() {//add all hsd mapping annotation methods to entrypointList<JClass> list = solver.getHierarchy().applicationClasses().toList();for (JClass jClass : list) {jClass.getDeclaredMethods().forEach(jMethod->{if (!jMethod.getAnnotations().stream().filter(annotation -> annotation.getType().matches("org.springframework.web.bind.annotation.\\w+Mapping")).toList().isEmpty()) {solver.addEntryPoint(new EntryPoint(jMethod, EmptyParamProvider.get()));}});}}
}

然后在pointer Analysis直接加入該插件,然后執行程序

然后執行程序將dot轉換為svg
dot -Tsvg -o taint-flow-graph.svg taint-flow-graph.dot

由于上邊我們只加入了一個sources和sql的sink點,所以只能檢測出來一個taintflow

2.2 SourceHandler 分析及springboot source 添加

污點分析的核心包括如下三個集成到指針分析的核心插件:
SourceHandler:添加代表污點的特殊堆抽象加入到符合source點規則的指針的指向集中
TransferHandler:將符合污點傳播規則的邊加入指針分析
SinkHandler:收集污點流,輸出source->sink的污點流的集合

2.2.1 source類型

tai-e的污點分析支以下持三種source

sources:- { kind: call, method: "<javax.servlet.ServletRequestWrapper: java.lang.String getParameter(java.lang.String)>", index: result }- { kind: param, method: "<com.example.Controller: java.lang.String index(javax.servlet.http.HttpServletRequest)>", index: 0 }- { kind: field, field: "<SourceSink: java.lang.String info>" }

call sources
source點由調用點生成,若call site語句調用了特定方法,那么返回值就是source點。
paramater sources
對于特定方法,例如入口方法,沒有特定的調用點。但其形參依然可能是source點。在spring-boot,通過注解來聲明請求的處理入口,沒有明確調用controller方法,在這種情況下,paramater sources非常有用。
field sources
對于字段類型的指針,其依然可能是source。

2.2.2 流程分析

從配置中獲取source點的配置

當指針分析中產生新的語句或新的調用邊時,若語句符合source的規則,則代表指針即為source點

當指針分析產生新的方法時,會處理其中的語句,也會在這個地方處理paramater sources

若我們想添加自定義的source點,便可以在handleParamSource、handleFieldSource、handleCallSource中添加。

2.2.3 添加source

我們的source僅加入了一個,但是一條一條加source也不太現實,沒辦法實現通用型。
通過分析找到2個比較適合加source點的地方,一個是處理source的開始,一個是處理source結束的地方。
1. SourceHandler處理ParamSource的地方

2. 在tai-e讀取taint-config文件解析后添加source

我們這里就看第一種方法吧

代碼如下

private void handleParamSource(CSMethod csMethod) {JMethod method = csMethod.getMethod();if (paramSources.containsKey(method)) {Context context = csMethod.getContext();IR ir = method.getIR();paramSources.get(method).forEach(source -> {IndexRef indexRef = source.indexRef();Var param = ir.getParam(indexRef.index());SourcePoint sourcePoint = new ParamSourcePoint(method, indexRef);Obj taint = manager.makeTaint(sourcePoint, source.type());switch (indexRef.kind()) {case VAR -> solver.addVarPointsTo(context, param, taint);case ARRAY, FIELD -> sourceInfos.put(param, new SourceInfo(indexRef, taint));}});}else {if (!method.getAnnotations().stream().filter(annotation -> annotation.getType().matches("org.springframework.web.bind.annotation.\\w+Mapping")).toList().isEmpty()) {Context context = csMethod.getContext();IR ir = method.getIR();for (int i = 0; i < ir.getParams().size(); i++) {Var param = ir.getParam(i);SourcePoint sourcePoint = new ParamSourcePoint(method, new IndexRef(IndexRef.Kind.VAR, i, null));Obj taint = manager.makeTaint(sourcePoint, param.getType());solver.addVarPointsTo(context, param, taint);}}}}

然后執行程序,查看結果,可以看到source都添加成功了,并且新增了一個taintflow。

?3. 結果展示

lcark、keanu大佬實現更改的相關代碼以及配置文件已經上傳至github

具體食用方法如下:

1. 下載代碼,并移動至spring-boot-1目錄下

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

2. 將java-sec-code文件夾移至與Tai-e-demo文件夾相同目錄下

3. 將SpringBootHandler.java移動至Tai-e源碼的src/main/java/pascal/taie/analysis/pta/plugin/taint/目錄下,并重新編譯打包

4. 使用如下命令運行tai-e便可以成功獲取到掃描結果
java -cp xxx\tai-e-all-0.5.1-SNAPSHOT.jar pascal.taie.Main --options-file=options.yml

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/14817.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/14817.shtml
英文地址,請注明出處:http://en.pswp.cn/web/14817.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

OpenHarmony輕松玩轉GIF數據渲染

OpenAtom OpenHarmony&#xff08;以下簡稱“OpenHarmony”&#xff09;提供了Image組件支持GIF動圖的播放&#xff0c;但是缺乏擴展能力&#xff0c;不支持播放控制等。今天介紹一款三方庫——ohos-gif-drawable三方組件&#xff0c;帶大家一起玩轉GIF的數據渲染&#xff0c;搞…

如何在JS中克隆對象

在JavaScript中&#xff0c;克隆對象并不是直接支持的操作&#xff0c;因為JavaScript中的對象是通過引用傳遞的&#xff0c;而不是通過值傳遞。但是&#xff0c;你可以使用幾種不同的方法來"克隆"或"復制"一個對象。 1. 淺拷貝&#xff08;Shallow Copy&…

二手車經營效率羅盤,用經營效率羅盤玩轉二手車生意

課程下載&#xff1a;https://download.csdn.net/download/m0_66047725/89292198 更多資源下載&#xff1a;關注我。 帶你了解不一樣的二手車圈讓二手車經營更高效 課程介紹 隨著時代不斷發展&#xff0c;二手車行業迎來了快速變革期。二手車有著一車一況、一車一價非標和價…

無人機+飛行服務:無人機飛防服務(打藥+施肥+播種)技術詳解

無人機飛防服務&#xff0c;結合了先進的無人機技術與農業實踐&#xff0c;為現代農業提供了高效、精準的打藥、施肥和播種解決方案。以下是對這些技術的詳細解析&#xff1a; 一、無人機打藥技術 無人機打藥技術利用無人機搭載噴霧設備&#xff0c;對農田進行精準施藥。通過…

【數倉系列】maxcompute、postgresql、sparksql等行轉列數據處理實戰總結(其他類型持續總結更新)

1.熟悉、梳理、總結項目研發實戰中的SQL開發日常使用中的問題、經驗總結&#xff0c;都是常用的開發技能&#xff0c;可以省去很多時間&#xff0c;時間長就忘記了 2.歡迎點贊、關注、批評、指正&#xff0c;互三走起來&#xff0c;小手動起來&#xff01; 文章目錄 1.maxcompu…

關于java.nio.file 包--用于文件和文件系統操作的核心包之一

java.nio.file 包是 Java 中用于文件和文件系統操作的核心包之一。這個包提供了許多類和接口&#xff0c;用于在 Java 虛擬機中訪問文件、管理文件屬性和操作文件系統。主要的功能包括&#xff1a; 1.訪問文件和目錄: java.nio.file.Files 類提供了許多靜態方法&#xff0c;用于…

【Crypto】看我回旋踢

文章目錄 一、看我回旋踢二、知識點什么是ROT13&#xff1f;工作原理分析字符串格式 解題感悟 一、看我回旋踢 關鍵詞回旋&#xff0c;盲猜ROT13 因為以 synt{ 開頭&#xff0c;并以 } 結束&#xff0c;基本可以判斷是ROT13 小小flag&#xff0c;拿下&#xff01; 二、知識點 …

抖音極速版:抖音輕量精簡版本,新人享大福利

和快手一樣&#xff0c;抖音也有自己的極速版&#xff0c;可視作抖音的輕量精簡版&#xff0c;更專注于刷視頻看廣告賺錢&#xff0c;收益比抖音要高&#xff0c;可玩性更佳。 抖音極速版簡介 抖音極速版是一個提供短視頻創業和收益任務的平臺&#xff0c;用戶可以通過觀看廣…

leetcode-560 和為k的數組

一、題目描述 給你一個整數數組 nums 和一個整數 k &#xff0c;請你統計并返回 該數組中和為 k 的子數組的個數 。 子數組是數組中元素的連續非空序列。 注意&#xff1a;nums中的元素可為負數 輸入&#xff1a;nums [1,1,1], k 2 輸出&#xff1a;2輸入&#xff1a;num…

裝飾乙級資質延期申請的注意事項

在申請裝飾乙級資質延期時&#xff0c;企業需要注意以下幾個重要事項&#xff1a; 提前了解政策和要求&#xff1a; 企業應提前了解并熟悉資質延期的相關政策和要求&#xff0c;包括所需材料、辦理流程、時間限制等。這有助于企業做好充分準備&#xff0c;避免在申請過程中出現…

【機器學習聚類算法實戰-5】機器學習聚類算法之DBSCAN聚類、K均值聚類算法、分層聚類和不同度量的聚集聚類實例分析

&#x1f3a9; 歡迎來到技術探索的奇幻世界&#x1f468;?&#x1f4bb; &#x1f4dc; 個人主頁&#xff1a;一倫明悅-CSDN博客 ?&#x1f3fb; 作者簡介&#xff1a; C軟件開發、Python機器學習愛好者 &#x1f5e3;? 互動與支持&#xff1a;&#x1f4ac;評論 &…

MYSQL課堂練習

學生表:studentsno&#xff0c;sname&#xff0c;ssex&#xff0c;sage&#xff0c;sdept)學號&#xff0c;姓名&#xff0c;性別&#xff0c;年齡&#xff0c;所在系 sno為主鍵課程表:Course(cno&#xff0c;cname&#xff0c;) 課程號&#xff0c;課程名 cno為主鍵 學生選課…

申報照明工程設計乙級資質關于財務審計報告的要求

申報照明工程設計乙級資質時&#xff0c;關于財務審計報告的要求通常包括以下幾點&#xff1a; 審計報告類型&#xff1a;需要提供由具有法定資質的會計師事務所出具的財務審計報告。如果是企業已經運營滿一個會計年度&#xff0c;應提交最近一個完整會計年度的年度審計報告。如…

Rust:struct 與字節序列的相互轉換

在 Rust 中&#xff0c;將結構體&#xff08;struct&#xff09;與字節序列&#xff08;Vec<u8>&#xff09;相互轉換的常見方法是使用序列化和反序列化庫。Rust 有一個流行的序列化庫叫做 serde&#xff0c;它支持多種數據格式。為了將結構體轉換為字節序列&#xff0c;…

保障餐飲場所安全:定期送檢可燃氣體報警器

在餐飲行業&#xff0c;火災隱患一直備受關注。餐廳、茶飲店等場所常常使用燃氣設備&#xff0c;而這些設備帶來了潛在的安全隱患。 為了及時發現并預防可燃氣體泄漏&#xff0c;可燃氣體報警器的定期送檢顯得尤為重要。那么&#xff0c;為什么可燃氣體報警器需要定期送檢呢&a…

【MySQL精通之路】系統變量-動態系統變量

許多服務器系統變量是動態的&#xff0c;可以在運行時進行設置。 參見“變量賦值的SET語法”。 有關設置系統變量的權限要求的描述&#xff0c;請參閱“系統變量權限” 【MySQL精通之路】系統變量-系統變量權限-CSDN博客 下表列出了所有適用于mysqld的動態系統變量。 該表列出…

java 設計模式(三)-- 單例模式

引言 單例模式是一種常用的軟件設計模式&#xff0c;它確保一個類只有一個實例&#xff0c;并提供一個全局訪問點來獲取這個實例。單例模式在Java中實現起來相對簡單&#xff0c;但實現方式有多種&#xff0c;每種方式都有其特點和適用場景。 一、單例模式的實現方式 1. 懶漢…

【Linux】從零開始認識進程間通信 —— 管道

送給大家一句話&#xff1a; 人要成長&#xff0c;必有原因&#xff0c;背后的努力與積累一定數倍于普通人。所以&#xff0c;關鍵還在于自己。 – 楊絳 從零開始認識進程間通信 1 為什么要進程間通信2 進程如何通信3 進程通信的常見方式4 管道4.1 什么是管道4.2 管道通信的系…

交叉編譯程序,提示 incomplete type “struct sigaction“ is not allowed

問題描述 incomplete type "struct sigaction" is not allowed解決辦法 在代碼的最頂端添加如下代碼即可 #define _XOPEN_SOURCE此定義不是簡單的宏定義&#xff0c;是使程序符合系統環境的不可缺少的部分 _XOPEN_SOURCE為了實現XPG&#xff1a;The X/Open Porta…

零一萬物Yi-1.5開源,34B/9B/6B多尺寸,34B超Qwen1.5-72B

前言 近年來&#xff0c;大型語言模型&#xff08;LLM&#xff09;在各個領域展現出驚人的能力&#xff0c;為人們的生活和工作帶來了巨大的改變。然而&#xff0c;大多數開源 LLM 的性能仍然無法與閉源模型相媲美&#xff0c;這限制了 LLM 在科研和商業領域的進一步應用。為了…