强化學習篇:一次安全漏洞分析

kali_Ma 2021-09-18 21:24:18 阅读数:628

强化 一次 安全漏洞 安全 漏洞

前言

本文主要講述了在複現以及分析CVE-2021-26084過程的遇到的一些疑惑。其次,本文對該漏洞進行了一個相對完整的漏洞鏈的分析。由於筆者初次分析Confluence的漏洞,難免有所不足,懇請各比特評論區點評。

Confluence是一個團隊協作軟件,用於知識分享(WIKI)和團隊協作。Confluence將工作的環境稱為空間,比如為每個項目創建一個空間,設置用戶權限,通過pages添加wiki、想法、事件等等。

該漏洞有多個觸發點,但不需要授權的觸發點比特於:pages/createpage-entervariables.vm,本文將圍繞該觸發點進行分析。

2021最新整理網絡安全/滲透測試/安全學習/100份src技術文檔(全套視頻、大廠面經、精品手册、必備工具包、路線)一>點我<一

環境搭建

本次漏洞分析采用了docker環境Confluence 7.12.4版本。

Ognl錶達式注入分析

從補丁文件:cve-2021-26084-update.sh發現本次補丁只是針對5個.vm結尾的模板文件做了字符串替換,並沒對代碼邏輯進行更改。具體細節如下:

  1. 修改confluence/users/user-dark-features.vm

    value='$!action.featureKey' => value=featureKey
    

    7.12.4版本已經對該文件進行了更改

  2. 修改confluence/login.vm

    value='$!action.token' => value=token
    

    7.12.4版本已經對該文件進行了更改

  3. 修改confluence/pages/createpage-entervariables.vm

    value='$!querystring' => value=querystring
    value='$linkCreation' => value=linkCreation
    
  4. 修改confluence/template/custom/content-editor.vm

    對多個input標簽進行了value的替換,主要是將value中的$去掉

    "Hidden" "name='linkCreation'" "value='$isLinkCreation'" => "Hidden" "name='linkCreation'" "value=isLinkCreation"
    
  5. 修改JAR文件的中templates/editor-preload-container.vm

    value='$!{action.syncRev}' => value=syncRev
    

綜合上述5處改動,1和2不存在於7.12.4版本,3和4觸發點的input標簽相同,但4和5需要授權。所以此處對3號觸發點進行分析,3號觸發點的input標簽如下:

<form name="filltemplateform" method="POST" action="doenterpagevariables.action">
#form_xsrfToken()
#tag ("Hidden" "name='queryString'" "value='$!queryString'")
#tag ("Hidden" "name='templateId'" "value='$pageTemplate.id'")
#tag ("Hidden" "name='linkCreation'" "value='$linkCreation'")
#tag ("Hidden" "name='title'" "value=title")
#tag ("Hidden" "name='parentPageId'" "value=parentPageId")
#tag ("Hidden" "name='fromPageId'" "value=fromPageId")
#tag ("Hidden" "name='spaceKey'" "value=spaceKey")

結合github上的分析文章[^3],出漏洞的點在於queryString、linkCreation。觀察這6個標簽,我產生了如下問題:

  • 為什麼queryString可以觸發而title觸發不了,即$符號扮演的角色?
  • pageTemplate.id也有$符號,為什麼它不是漏洞觸發點?
  • 如何繞過單引號限制?

帶著這3個問題,我開始深入的分析該漏洞。首先,分析整個漏洞的觸發過程,由於漏洞是由Ognl錶達式注入造成,所以可以先對含有Ognl.getValue的代碼下斷點,對WEB-INF/lib進行反編譯後,我找到了如下3個地方:

com/opensymphony/xwork/util/OgnlUtil.java#copy()

image.png

com/opensymphony/webwork/views/jsp/ui/OgnlTool.java#findValue()

image.png

com/opensymphony/xwork/util/OgnlValueStack.java

image.png

對這幾個點打上斷點後,我開始調試Confluence,經過測試發現觸發斷點的代碼在com/opensymphony/xwork/util/OgnlValueStack.java

image.png

image.png

為了理清整個輸入的處理過程,需要從上遊開始分析,如圖7所示,左側可以發現此處要進入WebWork的對doenterpagevariablesaction進行處理。

image.png

跟進處理函數,來到Velocity模板處理類,如圖8所示,首先會通過getTemplate加載finalLocation指定的模板,然後通過處理context,將結果寫入writer。

image.png

來到Template類的處理邏輯,通過將模板生成的語法樹轉化為SimpleNode節點進行處理。從圖9 右側的變量區可以看到模板一共生成了8個子樹,input標簽比特於7號子樹。

image.png

image.png

如圖所示,最終會通過AbstractTagDirective類對標簽進行處理。如圖12所示,processTag函數通過doEndTag函數調用evaluateParamsOgnlValueStack中獲取相關變量的值,如name=queryString

image.png

image.png

evaluateParams函數需要關注兩個地方,第一是通過nameAttr計算name。即把'queryString'變成name=queryString

image.png

重點關注第二處,即value=xxx的計算。

image.png

進入findValue函數,在圖15中可以看到在真正的去計算Ognl錶達式前,會調用靜態方法SafeExpressionUtil.isSafeExpression對編譯後的結果進行安全檢查。一共包括四個方面:

  1. 第一個hashset限制了構造函數的關鍵字:new,靜態方法調用:@符號
  2. 第二個和第三個hashset限制了獲取classloader,如:xxx.class或者xxx.getClass()
  3. 第四個hashset限制了編譯後的結果中不能出現特定的變量

這裏繞過方式可以使用數組進行繞過,如:""["class"].forName[^4]

image.png

圖15 黑名單檢查

findvalue通過OgnlValueStack#findValue實現了對錶達式的計算,如圖16所示,OgnlUtil會正確的識別\u0027',將錶達式變成一個完整Ognl錶達式,最終調用Ognl.getValue計算錶達式。

image.png

疑問解答

1. 單引號的處理邏輯

先說答案:處理tag時會從OgnlValueStack中根據nameattr和valueAttr取值並計算,這兩個屬性通過applyAttributes設置,applyAttributes用Ognl在初始的context上下文中獲取到parameters提交的值,經過ConfluenceHtmlEntityEncodingPolicyHTML實體編碼類處理。所以'會被實體編碼,但由於Ognl錶達式可以正常處理unicode編碼的單引號\u0027,所以可以用unicode編碼替代。

第二節中分析了一個完整的觸發流程,但需要注意的是該payload中利用了unicode編碼:'=>\u0027。那麼為什麼'不行呢?看到上文的processTag部分,如圖17所示,processTag需要的參數通過object傳入。

image.png

將輸入改為:queryString=aaa'%2b#{2*1}%2b\u0027bbb。跟進applyAttributes函數,該函數用createPropertyMap創建一個MAP對象用於接下來的屬性設置,createPropertyMap主要調用putProperty函數,其主要邏輯比特於node.value函數。

image.png

經過跳轉會進入ASTReference的處理邏輯,首先通過execute方法從上下文中取值(這裏實際上也是用OgnlValueStack的findValue來做)。此函數先不做分析,繼續來到EventHandlerUtil.referenceInsert(this.rsvc, context, this.literal(), value),該函數中會用HTML實體編碼處理單引號

image.png

image.png

2. $符號作用

在1中講到:

applyAttributes函數用createPropertyMap創建一個MAP對象用於接下來的屬性設置,createPropertyMap主要調用putProperty函數,其主要邏輯比特於node.value函數。

為了知道有無$符號的區別,需要知道node.value具體取值的邏輯。該函數根據節點樹的屬性:interpolate判斷是否該通過Ognl進行計算,如圖21所示,此時計算的是queryString的值,queryString的標簽為:#tag ("Hidden" "name='queryString'" "value='$!queryString'"),帶有$符號,其interpolate屬性為true,會通過Ognl計算。

那麼title如何呢?

image.png

title由於沒有設置$,被當成字符串。所以只會原原本本的返回value=title,而最終通過OgnlValueStack進行計算的也只是expr="title"

image.png

3. pageTemplate.id也有$符號,為什麼它不是漏洞觸發點?

為了弄清$pageTemplate.id沒觸發的原因,將輸入改為:templatePage=aaa\u0027%2b#{2*1}%2b\u0027bbb,在rootString為pageTemplate時截斷,如圖23所示。此時獲取到的值已經為null,證明OgnlValueStack中存放的值也是null,pageTemplate的值在這之前已經被設置為null。當value為null時,會使用nullString替代

image.png

image.png

既然之前就已經設置了OgnlValueStack中pageTemplate的值,則需要對OgnlValueStack中setValue函數下斷點

image.png

經過多次跳轉,來到圖26所示,通過OgnlRuntime.hasSetProperty函數判斷是否該設置屬性。

image.png

判斷方法設置屬性的方法是否存在

跟進該函數後,該函數通過getClass方法獲取了PageVariablesAction類。然後判斷其是否有setxxx的方法,如:queryString=>setqueryString()。如圖27所示。而PageVariablesAction類及其繼承的父類都不存在setpageTemplate方法,所以pageTemplate只能為null。

image.png

版权声明:本文为[kali_Ma]所创,转载请带上原文链接,感谢。 https://gsmany.com/2021/09/20210918212418057x.html