使用doop識別最近commons text漏洞的污點信息流- vivo互聯網技術- 科技資訊
Jiking 2023-06-23 Article作者:vivo 互聯網安全團隊- Chen Haojie
本文基於筆者對doop靜態程序分析框架源代碼和規則學習,並結合對目前漏洞公開技術細節的學習,修改增強doop app only模式下的分析規則後,實現通過doop工具識別commons text rce漏洞(CVE-2022-42889)。內容包含三部分,第一部分簡單介紹doop分析框架,第二部分簡單介紹commons text漏洞的原理和代碼調用棧,第三部分重點介紹如何改造doop app only模式下的規則以識別commons text漏洞的污點信息流。
一、doop靜態分析框架簡介
1. doop靜態分析框架簡介
doop靜態分析框架由希臘雅典大學plast-lab Yannis Smaragdakis團隊設計開發,目前看是一款開源領域的比較先進的程序靜態分析框架,一些程序靜態分析論文的理論也有通過doop的規則實現後實驗。
doop整體架構簡單明了,符合通常靜態代碼漏洞掃描工具掃描器內核的設計思路。架構上由groovy寫的調用程序“粘合”在一起,通過調用fact-generator和datalog分析器,得出自動化的分析結果。
下面是筆者畫的doop整體架構圖,包含doop中一些關鍵的組件模塊:
2. doop工作流程
-
doop的fact generator模塊會對輸入進行解析(例如jar包的解析或者類的resolve從而加載進必要的類信息到內存中)
-
調用soot、wala等工俱生成jimple IR,在此基礎上生成後續分析引擎需要的facts文件。而後doop使用LogicBlox(目前doop已不維護)或者Soufflé(開源的datalog分析引擎)
-
基於facts文件和既定的datalog分析規則文件進行分析,得到最終的程序分析結果。
doop支持對java源碼及字節碼的分析,不過源碼的jdk版本受限,建議直接使用字節碼進行分析。
doop核心是其實現的一套datalog分析規則,其中包含了由粗糙到精細的context-insensitive、1-call-site-sensitive、1-call-site-sensitive+heap的豐富的靜態程序分析策略等等等,同時通過在addons中添加了額外的對信息流分析、對spring等生態框架、對java反射特性的支持,十分強大。
以上是對doop的架構和功能的簡單介紹,jar包信息的解析、規則的預處理、編譯執行和解釋執行、程序的並發設計或者由於大量sootclass加載造成的內存溢出問題等一些細節由於篇幅限制不在此介紹。
二、commons text rce漏洞簡介
先對該漏洞進行簡單介紹。
Apache Commons Text是一款處理字符串和文本塊的開源項目,之前被披露存在CVE-2022-42889遠程代碼執行漏洞,這個漏洞目前網上的分析文章比較多,在此不做複述。該漏洞原理上有點類似log4j2,當然影響不可相比,其代碼中存在可以造成代碼執行的插值器,例如ScriptStringLookup(當然這裡提到這個插值器是因為我們目標就是分析這一條sink污點流),同時沒有對輸入字符串的安全性進行驗證導致問題。
借用網上公開的poc觸發ScriptStringLookup中的代碼執行,使用commons text 1.9版本:
完整的漏洞調用棧如下:
從調用棧可以看出,通過調用commons text的字符串替換函數,可以調用到ScriptStringLookup類的lookup方法,從而調用scriptEngine.eval執行代碼。可以看出該條漏洞鏈路較淺,但鏈路關鍵節點也涉及了接口抽像類的cast、輸入字符串的詞法分析狀態機以及各種字符串的處理函數,作為實驗對象非常合適。
三、commons text rce污點信息流的doop識別規則
我們選取上述二中commons text中
org.apache.commons.text.StringSubstitutor replace函數作為source,ScriptEngine eval函數作為sink。
doop設置app only模式去進行分析,doop在app only模式下會將!ApplicationMethod(?signature)加入isOpaqueMethod(?signature),這樣一些分析不會進入jdk的類中,可以大大提高doop的分析效率。依據萊斯定理,靜態程序分析難以達到完全的完備(truth或者perfect),也是盡可能優化sound。類似在企業級的SAST部署使用也是如此,也需要在掃描精度、掃描速度以及實際可用性中進行取捨或者平衡,所以doop的app only模式下在個人看來更接近實際嵌入到devsecops中的輕量級靜態代碼漏洞掃描的應用。
3.1 doop的datalog分析規則簡單介紹
由於涉及doop app only規則的改造,首先先簡單介紹doop使用的datalog規則。
doop目前維護使用開源的Soufflé分析datalog規則。 datalog是聲明式的編程語言,也是prolog語言的非圖靈完備子集,所以本質上也是建立在形式邏輯中的一階邏輯上。所以基礎概念也是命題推導,在Soufflé的形式上就是表現為關係(relation)。
如下例子:
很明顯可以看出該例子通過datalog定義的關係邏輯實現相等關係的自反性、對稱性和傳遞性,首先定義了equivalence關係,該關係可以由rel1和rel2關係蘊涵得到,而equivalence的a需要滿足關係rel1,b需要滿足關係rel2。具體語法和高階特性可以通過souffle-lang.github.io網站進行了解。
3.2 doop配置使用簡單介紹
doop可以通過gradle去編譯使用,需要提前在類unix系統中藉助cmake編譯安裝Soufflé,doop的具體安裝使用可以在https://github.com/plast-lab/doop-mirror中了解。
對doop的命令行使用進行簡單,分析,有幾個關鍵的命令參數,-i參數接受需要分析的文件(例如jar包),-a參數配置分析策略(例如是選擇context sensitive還是context insensitive),–app-only參數配置開啟doop的app only模式,–information-flow開啟doop的信息流分析模式(可以用來做污點分析),–platform設置分析需要的jdk平台,–fact-gen-cores配置生成facts的並發性。
本文使用的doop命令參數:
-a context-insensitive –app-only –information-flow spring –fact-gen-cores 4 -i docs/commons-text.jar –platform java_8 –stats none
3.3 重新編譯打包commons text
這是我最初使用doop分析commos text的方法,主要為了盡可能減輕的對原生規則的侵入。 doop在使用jackee進行分析事,分析入口的確定及一些mockobject的構建都需要依賴於對springmvc註解的識別。
下載commons text的源碼,自定義兩條class和method註解TestctxTaintedClassAnnotation、TestctxTaintedParamAnnotation:
註解實現為一個空註解,主要是為了標註一下我們的source,將註解打到對應的class類和方法:
重新編譯打包為jar包,得到2中命令參數-i的commons-text.jar。
3.4 改造doop app only下的規則
doop的污點信息流識別依賴於指針分析結果,同時也依賴污點轉移函數。 doop中已經預置了多條污點轉移函數,其中包含了字符串、鍊錶、迭代器等基礎類方法。
ParamToBaseTaintTransferMethod(0, "<java.lang.StringBuffer: java.lang.StringBuffer append(java.lang.Object)>").
ParamToBaseTaintTransferMethod(0, "<java.lang.StringBuffer: java.lang.StringBuffer append(java.lang.String)>").
ParamToBaseTaintTransferMethod(0, "<java.lang.StringBuffer: java.lang.StringBuffer append(java.lang.StringBuffer)>").
ParamToBaseTaintTransferMethod(0, "<java.lang.StringBuffer: java.lang.StringBuffer append(java.lang.CharSequence)>").
ParamToBaseTaintTransferMethod(0, "<java.lang.StringBuffer: java.lang.StringBuffer append(char[])>").
ParamToBaseTaintTransferMethod(0, "<java.lang.StringBuffer: java.lang.StringBuffer append(char)>").
BaseToRetTaintTransferMethod("<java.lang.Float: float floatValue()>").
BaseToRetTaintTransferMethod("<java.lang.String: byte[] getBytes(java.lang.String)>").
BaseToRetTaintTransferMethod("<java.lang.String: char charAt(int)>").
BaseToRetTaintTransferMethod("<java.util.Enumeration: java.lang.Object nextElement()>").
BaseToRetTaintTransferMethod("<java.util.Iterator: java.lang.Object next()>").
BaseToRetTaintTransferMethod("<java.util.LinkedList: java.lang.Object clone()>").
BaseToRetTaintTransferMethod("<java.util.LinkedList: java.lang.Object get(int)>").
BaseToRetTaintTransferMethod("<java.util.Map: java.util.Set entrySet()>").
BaseToRetTaintTransferMethod("<java.util.Map$Entry: java.lang.Object getValue()>").
BaseToRetTaintTransferMethod("<java.util.Set: java.util.Iterator iterator()>").
BaseToRetTaintTransferMethod("<java.lang.String: char[] toCharArray()>").
BaseToRetTaintTransferMethod("<java.lang.String: java.lang.String intern()>").
然而其中沒有包含String split函數的污點轉移規則,需要添加上:
BaseToRetTaintTransferMethod("<java.lang.String: java.lang.String[] split(java.lang.String,int)>").
如上述,doop自有的jackee規則肯定沒有包含我們自定義的註解,所以需要在EntryPointClass、Mockobj等關係定義中添加對我們自定義的class污點註解的識別。
EntryPointClass(?type) :-
Type_Annotation(?type, "org.apache.commons.text.TestctxTaintedClassAnnotation");
MockObject(?mockObj, ?type) :-
Type_Annotation(?type, "org.apache.commons.text.TestctxTaintedClassAnnotation");
同時也需要添加param污點的註解。doop需要通過這些註解識別分析入口方法,構建污點mockobj,建立初始的指向關係等。
mainAnalysis.VarPointsTo(?hctx, cat(cat(cat(cat(?to, "::: "), ?type), "::: "), "ASSIGN"), ?ctx, ?to) :-
FormalParam(?idx, ?meth, ?to),
(Param_Annotation(?meth, ?idx, "org.springframework.web.bind.annotation.RequestParam");
Param_Annotation(?meth, ?idx, "org.springframework.web.bind.annotation.RequestBody");
Param_Annotation(?meth, ?idx, "org.apache.commons.text.TestctxTaintedParamAnnotation");
為了確保方法的可達性,我們還添加了
ImplicitReachable(“”) :- isMethod(“”).但後續看不一定有必要,僅供參考。
通過註解我們在規則中定義了source,接下來需要定義sink,我們將ScriptEngine的eval方法定義為sink:
LeakingSinkMethodArg("default", 0, method) :- isMethod(method), match("<javax.script.ScriptEngine: java.lang.Object eval[(].*[)]>", method).
正如前述,由於是在app only下,doop下通過OpaqueMethod關係過濾了jdk類的識別,這樣會導致相應的上述預置的污點轉移函數無法完成污點轉移,所以需要另外定制規則流去將轉移函數包含進數據流分析過程。
於是需要定義
OptTaintedtransMethodInvocationBase關係。
.decl OptTaintedtransMethodInvocationBase(?invocation:MethodInvocation,?method:Method,?ctx:configuration.Context,?base:Var)
OptTaintedtransMethodInvocationBase(?invocation,?tomethod,?ctx,?base) :-
ReachableContext(?ctx, ?inmethod),
Instruction_Method(?invocation, ?inmethod),
(
_VirtualMethodInvocation(?invocation, _, ?tomethod, ?base, _);
_SpecialMethodInvocation(?invocation, _, ?tomethod, ?base, _)
).
在此基礎上,為了完成新的污點轉移,doop需要根據以下自定義規則分析出返回值的類型信息。
.decl MaytaintedInvocationInfo(?invocation:MethodInvocation,?type:Type,?ret:Var)
MaytaintedInvocationInfo(?invocation, ?type, ?ret) :-
Method_ReturnType(?method, ?type),
MethodInvocation_Method(?invocation, ?method),
AssignReturnValue(?invocation, ?ret).
.decl MaytaintedTypeForReturnValue(?type:Type, ?ret:Var, ?invocation:MethodInvocation)
MaytaintedTypeForReturnValue(?type, ?ret, ?invocation) :-
MaytaintedInvocationInfo(?invocation, ?type, ?ret),
!VarIsCast(?ret).
基於以上的污點轉移過程分析規則,應用到污點變量的轉移分析規則中。
VarIsTaintedFromVar(?type, ?ctx, ?ret, ?ctx, ?base) :-
mainAnalysis.OptTaintedtransMethodInvocationBase(?invocation,?method,?ctx,?base),
MaytaintedTypeForReturnValue(?type, ?ret, ?invocation),
BaseToRetTaintTransferMethod(?method).
同時也需要重新定義LeakingSinkVariable關係,因為我們這裡自定義的sink方法也是Opaque方法,這樣才能識別到我們的ScriptEngine 的eval方法。
LeakingSinkVariable(?label, ?invocation, ?ctx, ?var) :-
LeakingSinkMethodArg(?label, ?index, ?tomethod),
mainAnalysis.OptTaintedtransMethodInvocationBase(?invocation,?tomethod,?ctx,?base),
ActualParam(?index, ?invocation, ?var).
從上面規則的定義可以看出,改造的流程還是比較清晰的,並且通過關係的名字,這些關係的含義和用途也很容易理解。添加這些自定義規則到我們的doop分析中運行,在結果中可以看出,doop完成了對commons text的污點信息流的識別。
在結果集中的LeakingTaintedInformation.csv文件中可以找到我們需要捕捉到的souce-sink流。
default default <<immutable-context>> <org.apache.commons.text.lookup.ScriptStringLookup: java.lang.String lookup(java.lang.String)>/javax.script.ScriptEngine.eval/0 <org.apache.commons.text.StringSubstitutor: java.lang.String replace(java.lang.String)>/@parameter0
LeakingTaintedInformation.csv給出了污點信息。包括污點的標籤(這裡是默認的default,可以自定義),sink方法的調用信息,該sink方法對應的污點源頭souce信息。
如上圖可以看出,
org.apache.commons.text.lookup.ScriptStringLookup:
java.lang.String lookup(java.lang.String)中調用到
javax.script.ScriptEngine.eval,並且污點的源頭是
org.apache.commons.text.StringSubstitutor:
java.lang.String replace(java.lang.String)方法的參數@parameter0。
同時,在結果集中的AppTaintedVar.csv文件也可以看到具體的應用代碼中由於污點傳播過程中的被污染的變量.以上面commons text 漏洞執行方法棧中的
org.apache.commons.text.StringSubstitutor的resolveVariable為例:
可以看出方法中被污染的入參variableName、buf,還有resolver,以及$stack7等(這是經過soot生成jimple的過程中SSA pack部分優化新增的棧變量)。
基於這兩個結果集基本可以看出漏洞的觸發流程或者說污點的傳播過程(雖然不是特別直觀),如果需要也可以再搭配生成的CallGraphEdge.csv去更方便的進行分析。
四、總結
doop直接用來分析大型項目需要一定的計算資源,並且無論是規則的定制還是分析結果查看都不是特別直觀,畢竟它的設計初衷就是一款分析框架,用在實際漏掃漏洞挖掘中可能需要進一步包裝修改。但可以看出,doop作為一款優秀的開源靜態分析框架,在算法上毋庸置疑是比較先進和豐富的,而且基於開源的算法規則,我們可以任意去定制我們需要的分析邏輯。其與codeql在設計思路也較為相近,將程序信息提取後生成數據庫,開放查詢接口,將程序分析轉變為數據關係的查詢,因此可以擴展出更多的用途。
END
猜你喜歡
#使用doop識別最近commons #text漏洞的污點信息流 #vivo互聯網技術 #科技資訊
You may also like
上海网信办对属地 46 款 App 收集使用个人信息情况开展专项检查 – 科技資訊
微信、QQ 全新 UOS 版本发布 – 科技資訊
代码层面探索前端性能 | 京东云技术团队 – 京东云开发者的个人空间 – 科技資訊
Gitee 推荐 | 为开发者打造的代码解释器 Octopus
DataSophon —— 云原生大数据管家
1-8 月我国规上互联网企业完成业务收入 9067 亿元 – 科技資訊
相关贴文:
- Lepton 無損壓縮原理及性能分析- vivo互聯網技術- 科技資訊
- 每日一博| 攻擊面分析及應對實踐
- 每日一博| vivo 互聯網機器學習平台的建設與實踐
- 每日一博| 從0 到1 設計通用數據大屏搭建平台
- 每日一博| 如何實現一個SQL 解析器
- vivo 雲原生容器探索和落地實踐- vivo互聯網技術- 科技資訊
- vivo全球商城:庫存系統架構設計與實踐- vivo互聯網技術- 科技資訊
- vivo 短視頻用戶訪問體驗優化實踐- vivo互聯網技術- 科技資訊
近期文章
- 您需要多少行銷預算來經營您的 Shopify 商店? #Hashlearning |
- 開始您的直銷之旅:初學者指南
- 如何從 Shopify 上的折扣和優惠券中排除產品
- 我嘗試了零預算印度直銷來購買新“手機” ‼ Shopify 直銷
- 將 Shopify 商店與 TikTok 商店連接並同步產品
- Shopify 教學:新增產品詳細資訊以實現更好的轉換 |冥河 | #shopify提示|阿南特
- 國際 Shopify 直銷的完整產品研究
- 點擊簡介中的連結立即開始免費試用 Shopify💻✅
- 如何在 Shopify 中自訂產品頁面 | Shopify 初學者教學 2024
發佈留言 取消回覆