Java程式碼審計篇 | ofcms系統審計思路講解 - 篇2 | SQL隱碼攻擊漏洞審計
1. 前言
我發現很多文章包括教程,大概套路是:只說有漏洞的點,將有漏洞的點指出,然後分析程式碼;或者黑盒測試出漏洞之後,然後分析程式碼。
我認為這是在分析漏洞程式碼,而非程式碼審計。程式碼審計文章或教程應該是從0開始找到漏洞所在,包括思路!
所以這裡不管有沒有漏洞,我都會把審計過程寫出來,因此篇幅會很長,但我認為這樣對你會很有幫助。
知其然亦知所以然。
由於篇幅較長,因此我會分幾篇進行,本篇是整個系列的第2篇,講解1個內容:
- SQL隱碼攻擊漏洞審計
搭建好環境,確定好專案結構之後,按我思路是應該審計專案所使用框架漏洞的,這裡關於框架漏洞就放最後篇章來說了,我們想了解下基礎漏洞的審計~
文章中有錯誤點,或者思路上有什麼問題的,歡迎師傅們留言指出~
2. SQL隱碼攻擊程式碼審計【有1處】
sql注入漏洞一般搜尋的關鍵字:
Statement
createStatement
PreparStatement
like "%{
in (${
select
update
insert
...
1)全域性搜尋Statement
關鍵字,發現有幾處,不過大多都是preparStatement
預編譯方式執行sql語句。
那要不要點選去看看?答案是需要!因為可能會有繞過方式...
2)點進第一個看看
核心程式碼已框出,就是預編譯執行sql語句~哦,戲不大。
不過大家可以思考一下:如果整個sql語句都可控呢?是不是可以繞過預編譯限制呢?
所以我們不要放棄,接下來看一下sql語句怎麼來的。
3)搜尋executeSQL()方法的呼叫,檢視sql語句怎麼傳遞進來的
在方法上右擊,然後“Find Usages”或Alt+F7檢視方法的呼叫:
發現有兩個,如下
有辦法注入嗎?貌似沒有,原因有2:
- sql語句是寫死的
- 引數是單獨傳入的,但是後期是需要經過預處理的
其實這裡還有一個點,就是這兩個方法是在安裝工具類InstallUtils
下,因此即使有sql注入點,也無法利用,畢竟你不可能去重新安裝該專案吧。
所以,接下來,安裝工具類InstallUtils
下的程式碼我們就不需要看了。
2.4. 4)我們搜尋的Statement
關鍵字,所處位置都是安裝工具類InstallUtils
,所以全部忽略。
接下來換關鍵字搜尋:
5)全域性搜尋like "%
關鍵字,發現有1處,不過是註釋,不需要管了。
6)全域性搜尋in (${
關鍵字,無
7)全域性搜尋select
關鍵字,很多,但是翻了一圈,沒有和sql語句相關的
8)全域性搜尋update
關鍵字,搜尋到了很多貌似和sql有關係的語句
並且可以發現一個共同點,大部分都是Db.update
呼叫的。
9)點進第一個看看,發現這個ComnController
類裡面的方法都和sql語句相關,那挨個看一下
10)先分析下query()方法
這裡發現,Db這個是什麼,點進去看一下,發現是專門用來運算元據庫的類:
自己寫的嗎?不不不,可以看到,該檔案是Db.class,可以下載原始碼
經過分析檢視,這個Db
是com.jfinal.plugin.activerecord
目錄下的一個類,原來是使用的jfinal
框架~ 是我孤陋寡聞了。
透過分析Db的原始碼,發現每個方法都使用了預編譯處理~ 有漏洞的可能性不大了
但是還有一種情況,就是前面所說的,整個sql語句可控,那麼可能會存在sql注入~
11)檢視每個方法的呼叫,發現整個sql語句可控的情況
當我們找到update(String sql)
方法的呼叫情況,SystemGenerateController
類的create()方法時,發現此處的sql語句是透過getPara()
方法直接獲取的,並沒有傳遞什麼引數
這裡大機率可以判定為sql語句可控,當然也不一定,需要看一下getPara()
方法是怎麼實現的:
點選進入看一下,發現是透過request.getParameter(name)
直接獲取的引數內容!
這個時候可以斷定,這裡99.9%存在sql注入,因為整個sql語句可控。
12)尋找對應的前端功能
既然得知,SystemGenerateController
類的create()
方法可以觸發該sql執行,那麼找一下前端哪個功能可以觸發該方法,這裡需要根據前面所說的路由機制來判斷。
可以看到類名上存在一個@Action(path = "/system/generate")
註解,並且方法名是create
,並且該類在admin目錄下
因此,可以推斷出,前端請求的路徑是/admin/system/generate/create.json
那麼接下來去前端搜尋一下:
- 注意點1:搜尋的時候不要搜全,因為路徑可能是拼接出來的
- 注意點2:這些路徑大部分都是在js檔案中,所以直接搜不一定搜出來,因為有些js檔案可能沒載入呢,所以搜尋的時候,需要不斷的點選不同功能來獲取到不同的js檔案(這裡可以根據路徑判斷大體的功能點)。
當我們點選到“程式碼生成”-“新建”的時候,出現了我們搜尋的路徑(真費時呀)。
再透過引數名,可以再進一步驗證該功能是正確的,如下圖:都為sql引數名。
2.13. 13)驗證漏洞
接下來,根據這個功能可以驗證該漏洞了。
但是這個功能是用來建立表的,透過原始碼,我們可以得出可以使用的sql指令是update。
既然只能使用update,那這裡我的思路大概就是:報錯注入
那麼接下來試一下,報錯注入,使用update報錯注入需要知道表名和列名,那我們可以去資料庫看一下~(注意:這裡是程式碼審計,不是黑盒,所以是可以得到資料庫資訊的)
那就隨機找個表名欄位名~
構造報錯注入語句:
update of_cms_field set is_disabled=updatexml(1,concat(0x5e,database(),0x5e),3) where field_id=2
點選新增,成功執行!
2.14. 14)繼續尋找其他sql語句可控的位置
好吧,找了其他的方法對應的呼叫,發現,不是sql語句固定,就是語句透過預編譯,沒有完全可控的sql語句了。ok,sql注入的程式碼審計到此結束。