天天看點

Java自動化審計(上篇)

Java自動化審計(上篇)

本文是 i 春秋論壇作家「Wker」表哥分享的技術文章,文章旨在為大家提供更多的學習方法與技能技巧,文章僅供學習參考。

CodeQl

CodeQL是一個免費開源的代碼語義分析引擎(GitHub購買之後的開源項目),其利用QL語言對代碼、執行流程等進行“查詢”,以此實作對代碼的安全性白盒審計,進行漏洞挖掘。

靶場

在網上找到的一個簡單的靶場,spring的項目,使用的jdk1.8。

CodeQl安裝

到目前為止,CodeQl已經更新到v2.7.3版本。

1、下載下傳CodeQl;

2、放入環境變量:export PATH=/Home/CodeQL/codeql:$PATH、source /etc/profile,友善我們後期使用vscode插件;

3、下載下傳codeql sdk;

4、下載下傳codeql vsc插件:

Java自動化審計(上篇)

隻需要幾步下載下傳就可以完成CodeQl環境的部署。

生成CodeQl資料庫

CodeQl并不提供文法樹解析,隻是提供對外查詢的接口,是以我們需要給他生成database幫助其進行查詢(這裡檢測的是我在網上clone下的靶場)。

codeql database create databasePath  --language="java"  --command="mvn clean install --file pom.xml" --source-root=sourcePath
      

databasePath:資料庫路徑(要儲存到那)

sourcePath:源檔案代碼存放路徑

執行完之後就會生成對應的資料庫,這裡需要注意mvn的路徑問題。

測試語句

1、首先用vscode打開codeql sdk,在ql/java/ql/src下建立一個test.ql來編寫測試腳本。

2、在codeql頁籤中打開之前建立的資料庫。

3、在test.ql中編寫select "hello word",右擊選擇執行ql,選擇測試的資料庫。

如果執行完畢之後出現如下界面,則說明環境搭建完畢。

Java自動化審計(上篇)

到此為止就可以在test.ql下編寫檢測腳本了。

CodeQl文法

和sql語句很類似,可以通過AST視圖檢視到目前資料庫中的内容:

Java自動化審計(上篇)

這裡簡單介紹基本的使用方法:

from [datatype] var
where condition(var = something)
select var
      

  

對應下面的:

from int i
where i = 1
select i
      

第一行指定的變量,第二行條件判斷,第三行輸出内容。

類庫可以通過檢視AST中的内容進行确定。

名稱 解釋
Method 方法類,Method method表示擷取目前項目中所有的方法。
MethodAccess 方法調用類,MethodAccess call表示擷取目前項目當中的所有方法調用。
Parameter 參數類,Parameter表示擷取目前項目當中所有的參數。

這隻是舉例說明,例如下面這段代碼:

import java

from Method method
select method
      

可以查詢出目前項目的所有方法。

下面這段是存在過濾的代碼:

import java

from Method method
where method.hasName("getStudent")
select method.getName(), method.getDeclaringType()
      

查找名稱為getStudent的方法和對應的類。

并且codeql提供了一種謂詞的方法幫助來分割複雜的邏輯代碼:

import java

predicate isStudent(Method method) {exists(|method.hasName("getStudent"))}

from Method method
where isStudent(method)
select method.getName(), method.getDeclaringType()
      

詳細的文法内容可以參考:https://codeql.github.com/docs/codeql-language-guides/basic-query-for-java-code/

污點分析

污點分析可以抽象成一個三元組〈sources, sinks, sanitizers〉的形式。其中,source即污點源,代表直接引入不受信任的資料或者機密資料到系統中;sink即污點彙聚點,代表直接産生安全敏感操作(違反資料完整性)或者洩露隐私資料到外界(違反資料保密性);sanitizer即無害處理,代表通過資料加密或者移除危害操作等手段使資料傳播不再對軟體系統的資訊安全産生危害。

污點分析就是分析程式中由污點源引入的資料是否能夠不經無害處理,而直接傳播到污點彙聚點,如果不能說明系統是資訊流安全的;否則,說明系統産生了隐私資料洩露或危險資料操作等安全問題。

簡單的了解是,source參數輸入的位置,sink危險函數執行的位置,sanitizers過濾函數。

通過定義上述三點内容可以定位出一條參數傳遞鍊,當然sanitizers可以不存在。

設定source

通過override predicate isSource(DataFlow::Node src) {}設定source,這是大多常用的source入口,包括spring的也在其中。

設定sink

override predicate isSink(DataFlow::Node sink) {
exists(Method method, MethodAccess call |
  method.hasName("query")
  and
  call.getMethod() = method and
  sink.a**pr() = call.getArgument(0)
)
}
      

上述代碼是一個謂語,查詢方法名為query的方法。

當然,目前檢測的是SQL注入,是以當jdbc執行query方法,則為進入了sink。

Flow資料流

from VulConfig config, DataFlow::PathNode source, DataFlow::PathNode sink
where config.hasFlowPath(source, sink)
select source.getNode(), source, sink, "source"
      

通過config.hasFlowPath(source, sink)設定source和sink,這樣codeql就可以幫助自動檢測漏洞,檢索調用鍊。

測試

import java
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.security.QueryInjection
import DataFlow::PathGraph

class VulConfig extends TaintTracking::Configuration {
  VulConfig() { this = "SqlInjectionConfig" }

  override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }

  override predicate isSink(DataFlow::Node sink) {
    exists(Method method, MethodAccess call |
      method.hasName("query")
      and
      call.getMethod() = method and
      sink.a**pr() = call.getArgument(0)
    )
  }
}

from VulConfig config, DataFlow::PathNode source, DataFlow::PathNode sink
where config.hasFlowPath(source, sink)
select source.getNode(), source, sink, "source"
      

上述是拷貝的他人寫好的,代碼也是上面所講,運作之後就可以看到所有進入query方法的鍊路了。

Java自動化審計(上篇)

可以點選對應的source和sink檢視位置,可以看到codeql已經幫我們整理出了5條調用鍊。

一步步跟蹤第一條調用鍊,可以得出完整的調用鍊路:

indexLogic.getStudent(username);
indexDb.getStudent(username);
String sql = "select * from students where username like '%" + username + "%'";
jdbcTemplate.query(sql, ROW_MAPPER);
      

至此,簡單的SQL注入就能查詢得到。

以上為今天分享的内容,小夥伴們看懂了嗎?

繼續閱讀