SpringBoot框架華夏ERP源碼審計
環境搭建
華夏ERP基於SpringBoot框架和SaaS模式,可以算作是國內人氣較高的一款ERP項目,看網上已經公開了漏洞,本次對此框架代碼進行源碼審計。
源碼下載路徑:https://github.com/jishenghua/jshERP,這里的版本為v2.3
直接拖入IDEA加載,Maven下載所需的jar包,點擊run即可
審計准備
典型的spring框架,先來看pom.xml加載了哪些威脅組件:
點根煙不慌,看到了這個熟悉的組件,版本透露出shell的感覺。
再來看一下Filter過濾器具體過濾了哪些內容,Servlet3.0提供了@WebFilter用於將一個類聲明為過濾器,搜索@WebFilter即可定位:
使用@WebInitParam配置多個name,對.css#.js#.jpg#.png#.gif#.ico,/user/login#/user/registerUser#/v2/api-docs資源請求的時候不會進行攔截,doFilter方法是具體的實現:
看到這里我們要明確:
- requestUrl中如果存在/doc.html,/register.html,/login.html字段就可以繞過認證請求
- 傳入verify()方法進行判斷的時候,正確的使用應該選擇endsWith()來判斷url是否以.css、.png這些資源后綴結尾,但是上圖代碼只是使用正則表達式判斷.css,.png名字存在即可,導致傳入諸如:../a.css/../,也可以繞過認證請求
- 使用startsWith()方法來判斷url是否以/user/login,/user/registerUser等字符開頭的時候,可以使用目錄穿越來騙過判斷,導致可以繞過認證請求
- 在Filter過濾器中沒有看到xss過濾,sql注入等惡意字符的過濾。
SQL注入
在之前的pom.xml文件中發現該框架使用的是Mybits的數據庫,找這類數據庫的注入,直接在*Mapper.xml文件中全局搜索 ${
點一個進去查看:
這種like型的模糊查詢使用了不安全的拼接,會直接參與SQL語句的編譯,惡意構造會導致SQL注入
回溯判斷對應的參數是否可控,搜索" selectByConditionUser ":
上面是一個數據處理層的接口類,繼續搜索" UserMapperEx.selectByConditionUser " 看具體在哪里調用:
看到service層的調用,繼續搜索" UserService.select( ":
可以看到參數userName,loginName是從search字段中獲取,判斷參數應該是可控的。下面的目的就是找前端接口,也就是Controller層的方法接口映射。
UserComponent類實現了ICmmonQuery這個接口,調用了此接口下的select方法
在同目錄下發現文件InterfaceContainer.java這個接口文件:
這里調用初始化函數init(),將service組件壓入configComponentMap中,后續調用getCommonQuery方法根據傳進來的apiName獲取對應的service組件(具體apiName跟對應的service組件映射如下:user->UserComponent)
InterfaceContainer對接口進行統一實例化處理,當apiName為user的時候,就會去實例化對應的UserComponent類,UserComponent類實現了ICmmonQuery這個接口,就會調用此接口ICmmonQuery類下的對應的方法。
所以InterfaceContainer類起到的是一個中轉分發的作用,關鍵在於哪個類調用getCommonQuery方法,並傳遞相應的apiName進去,搜一下" getCommonQuery( ":
這里判斷傳進來的apiName是否為控,繼續搜索 " CommonQueryManager ":
終於到Controller層了,上圖已經很清楚,實例化CommonQueryManager類的一個對象configResourceManager去調用select方法,傳入apiName,與參數集合paramterMap。
在環境上驗證一下:
在IDEA的Console控制台可以看到相應的sql語句打印:
當然還有:
粗濾看了一下,SQL注入太多了,這里不再演示:
權限校驗繞過
在審計准備階段對攔截器@WebFilter進行分析的時候,發現存在權限繞過的情況,來驗證第一種情況:
requestUrl中如果存在/doc.html,/register.html,/login.html字段就可以繞過認證請求
只要我們的請求url中有/doc.html,/register.html,/login.html字就可以繞過認證,payload可以這樣寫:/doc.html/../,/register.html/../,/login.html/../
正常無Sessionid請求:
會被重定向到登陸界面
加入payload請求:
成功繞過權限認證去訪問接口。
來驗證第二種情況:
傳入verify()方法進行判斷的時候,正確的使用應該選擇endsWith()來判斷url是否以.css、.png這些資源后綴結尾,但是上圖代碼只是使用正則表達式判斷.css,.png名字存在即可,導致傳入諸如:../a.css/../,也可以繞過認證請求
只要我們的請求url中有.css/.png/.jpg/.ico就可以繞過認證,payload可以這樣寫:/a.css/../,/a.jpg/../
正常無Sessionid請求:
會被重定向到登陸界面
加入payload請求:
成功繞過權限認證去訪問接口。
來驗證第三種情況:
使用startsWith()方法來判斷url是否以/user/login,/user/registerUser等字符開頭的時候,可以使用目錄穿越來騙過判斷,導致可以繞過認證請求
這個跟上面的利用方式一樣,使用穿越來繞過,payload可以這樣寫:/user/login/../../,/user/registerUser/../../,/v2/api-docs../../
正常無Sessionid請求:
會被重定向到登陸界面
加入payload請求:
成功繞過權限認證去訪問接口。
Fastjson反序列化命令執行
在審計准備的時候發現pom.xml加載了fastjson的組件,並且1.2.55確實是存在漏洞的版本。fastjson的核心在於調用了fastjson.JSON的parseObject函數將json字符串反序列化成對象,搜一下" parseObject( "調用:
調用的地方太多,這里有一個Util的文件,懷疑是不是通用的處理接口,跟進:
直接將search的內容傳入parseObject方法中進行解析,繼續搜索" StringUtil.getInfo( ",判斷傳進去的參數是否可控
看到這里就很舒服了,在SQL注入的時候已經分析過這里,search是從前端傳進來的參數,來構造payload:
search={"@type":"java.net.Inet4Address","val":"yvnan3.dnslog.cn"}
url編碼一下:
Dnslog平台已經收到了相應的請求
根據上面查找的結果,search接口全部都存在fastjson反序列化漏洞。
利用上面的登錄權限繞過,可未授權命令執行。
存儲型XSS
在之前對攔截器@WebFilter進行分析的時候,發現沒有對傳入的參數進行統一的xss過濾,代碼中也並未看到相關的轉義字符,前端接受惡意字符無過濾直接存入數據庫中,如下在某收入單的備注參數處插入xss payload:
看一下數據庫的語句:
可以看到無任何防護措施直接存入數據庫。
在代碼層看一下在從數據庫讀取數據的時候有沒有對數據進行轉義輸出:
直接將查詢出的結果以json的形式輸出,也沒有看到相關的過濾操作,導致存在存儲型XSS漏洞
其他參數也同樣存在此漏洞
越權密碼重置
在系統管理 - 用戶管理處 - 選擇一個用戶 - 重置密碼
抓取數據包
傳進去一個用戶id,就可以重置該用戶的密碼
進入代碼查看是否可以越權重置:
跟進service層具體查看一下resetPwd函數:
明顯看到這里只禁止重置admin超管密碼,但是並沒有對當前重置密碼的用戶身份做判斷,導致存在越權重置他人密碼,這里來驗證一下:
jsh用戶對應的用戶id為63
joker用戶對應的用戶id為132
jsh的用戶權限>joker的權限
使用joker用戶的身份去重置jsh用戶密碼:
利用上面的登錄權限繞過,可未授權重置根據用戶id重置用戶密碼(遍歷id重置所有用戶密碼)。
越權刪除用戶
這個漏洞的利用和上一個漏洞很像
在系統管理 - 用戶管理處 - 選擇一個用戶 - 刪除用戶信息
抓取數據包:
傳進去一個用戶ids,就可以刪除該用戶信息
進入代碼查看是否可以越權刪除:
跟進service層具體查看一下batDeleteUser函數:
接收參數ids,使用逗號,分割,調用userMapperEx.batDeleteOrUpdateUser()方法將ids參數拼接進sql語句進行刪除,這里沒有對當前執行刪除用戶操作的用戶身份做判斷,甚至沒有禁止刪除超級管理員,導致存在越權刪除任意用戶信息(包括管理員),這里來驗證一下:
ceshi用戶對應的用戶id為135
joker跟ceshi是平級賬戶
經過測試可以垂直越權刪除jsh等賬號
利用上面的登錄權限繞過,可未授權重置根據用戶ids刪除任意用戶
越權修改用戶信息
在系統管理 - 用戶管理處 - 選擇一個用戶 - 編輯用戶信息
抓取數據包:
關鍵參數是這個id跟info信息
跟進代碼:
跟進service層具體查看一下updateUserAndOrgUserRel函數:
跟進checkUserNameAndLoginName()方法:
由於用戶名和登錄名的校驗邏輯一樣,這里只拿登錄名檢查來說,首先通過getLoginName()獲取id對應的登錄名,再通過getUserListByUserNameOrLoginName()方法,將登錄名作為參數拼接進sql語句中獲取user列表,從列表中取出id與前端傳入的id進行比較,相同就可以更新數據。同樣沒有對當前執行更新用戶數據的操作的用戶身份做判斷,嘗試越權利用:
test123用戶對應的用戶id為131
joker跟test123是平級賬戶
成功越權修改他人的用戶信息
當然這個ERP系統的漏洞還有很多漏洞沒有列出來,包括越權查看郵件信息,未授權訪問敏感界面等,期待后續大佬們的挖掘。
如果有其他不錯的框架審計請在下面留言!