1. 引入
靜態應用程序安全測試(Static application security testing)簡稱SAST,是透過審查程式源代碼來識別漏洞,提升軟件安全性的作法。
Joern 是一個強大的開源靜態應用安全測試(SAST)工具,專注于代碼的語義分析。它通過將源代碼轉換為代碼屬性圖(Code Property Graph, CPG),并使用專用查詢語言 CPGQL 進行漏洞檢測。
CPGQL(Code Property Graph Query Language)是 Joern 平臺用于查詢代碼屬性圖(Code Property Graph, CPG)的專用查詢語言。CPG 是一種將源代碼的多種屬性(如語法結構、控制流、數據流等)整合為統一圖結構的表示方法,而 CPGQL 則提供了靈活強大的圖查詢能力。CPGQL 基于圖論,支持節點(Node)、邊(Edge)和路徑(Path)的查詢。
本文參考1中的查詢語句,復現部分CPGQL,目的是為了熟悉Joern的使用,更好的理解CPGQL。
2. 整體過程
如下C代碼與CPGQL均來自Joern官網(參考1)。
- 安裝Joern,參考2,本文在ubuntu22.04下進行
wget https://github.com/joernio/joern/releases/latest/download/joern-install.sh
chmod +x ./joern-install.sh
sudo ./joern-install.sh
注意,如果網速慢,需要打開joern-install.sh,對其中curl命令加proxy(curl -x "http:xxxxyyyzzzeeeddd"
)。
- 將如下有有缺陷的c語言代碼保存為
insecure_gets.c
int insecure_gets() {char str[DST_BUFFER_SIZE];gets(str);printf("%s", str);return 0;
}
這段代碼使用了 C 標準庫中的gets()函數,這是一個嚴重的安全隱患,可能導致緩沖區溢出攻擊。
- 使用Joern將C代碼轉換為代碼屬性圖CPG
/opt/joern/joern-cli/joern-parse insecure_gets.c --output insecure_gets.cpg.bin
- 使用Joern加載CPG
joern /data/yinbin/projects/ybresearch/joernlearn/insecure_gets.cpg.bin
- 在Joern的Shell中加載該CPG
joern> open("insecure_gets.cpg.bin")
val res2: Option[io.joern.console.workspacehandling.Project] = Some(value = Project(projectFile = ProjectFile(inputPath = "/data/yinbin/projects/ybresearch/joernlearn/insecure_gets.cpg.bin",name = "insecure_gets.cpg.bin"),path = /data/yinbin/projects/ybresearch/joernlearn/workspace/insecure_gets.cpg.bin,cpg = Some(value = Cpg[Graph[72 nodes]]))
)
使用open命令即可加載。
- 執行CPGQL
這里執行的CPGQL為({cpg.method("(?i)gets").callIn}).l
,含義如下:
cpg
:代表整個代碼屬性圖(Code Property Graph)的根節點。method("(?i)gets")
:查找名稱匹配正則表達式"(?i)gets"
的方法:(?i)
:正則修飾符,表示忽略大小寫(匹配gets
、GETS
、Gets
等)。gets
:目標函數名。
callIn
:獲取調用這些方法的所有調用點(即查找哪些代碼調用了gets()
)。.l
:將查詢結果轉換為列表并返回。
這個查詢等價于:
“找出代碼庫中所有調用了
gets()
函數的位置,無論大小寫。”
具體運行過程如下:
joern> ({cpg.method("(?i)gets").callIn}).l|
val res3: List[io.shiftleft.codepropertygraph.generated.nodes.Call] = List(Call(argumentIndex = -1,argumentName = None,code = "gets(str)",columnNumber = Some(value = 3),dispatchType = "STATIC_DISPATCH",dynamicTypeHintFullName = IndexedSeq(),lineNumber = Some(value = 3),methodFullName = "gets",name = "gets",offset = None,offsetEnd = None,order = 3,possibleTypes = IndexedSeq(),signature = "",typeFullName = "ANY")
)
這個結果說明:
- code = “gets(str)”
- 調用gets()的代碼行,參數為str(對應之前代碼示例中的char str[DST_BUFFER_SIZE])。
- lineNumber = Some(value = 3)
- 調用發生在第 3 行(與之前的代碼示例一致)。
- columnNumber = Some(value = 3)
- 調用從第 3 列開始(縮進后的位置)。
- methodFullName = “gets”
- 被調用方法的全名是gets。
- dispatchType = “STATIC_DISPATCH”
- 靜態調用(編譯時確定調用目標)。
3. 總結
本文給出了從安裝Joern到用Joern執行CPGQL找到C語言中不安全函數調用的流程的完整示例。
4. 參考
- joern官方查詢語句說明,https://queries.joern.io/
- 深入淺出Joern(一)Joern與CPG是什么,https://lorexxar.cn/2023/08/21/joern-and-cpg/