CDH6.3.2處理Zookeeper未授權訪問(安全漏洞)


前言

公司在做安全漏洞掃描。發現CDH Zookeeper存在未授權訪問入侵問題。

1.zookeeper的基本情況

zookeeper是分布式協同管理工具,常用來管理系統配置信息,提供分布式協同服務。zookeeper官網下載軟件包,bin目錄下有客戶端腳本和服務端腳本。另外還有個工具對理解和使用zookeeper服務非常有用,即zk-ui,該工具是zk服務端的可視化工具,可在web界面對服務端進行操作。

zookeeper以樹狀結構保存數據,我們完全可以對比linux文件系統理解zookeeper的文件系統。不同點在於linux下的每個目錄名對應一個znode。
zk-file-system.JPG
znode是zk的基本單元,可以存在數據信息、版本信息等等。如圖,/是zookeeper的根節點,A、B、C和D均為znode。

2.zookeeper存在的問題

我們在使用zookeeper提供的服務的時候會發現,只要知道zk服務端的IP和Port,任務用戶或者客戶端根本不需要任何的認證就可以連上zk的服務端,並且可以對znode進行增刪等操作。這樣數據是非常不安全的,極易被攻擊和篡改。

zookeeper解決這個問題的手段是ACL(access control list)機制,即訪問控制列表。

3.zookeeper的ACL機制

zookeeper通過ACL機制控制znode節點的訪問權限。

傳統的文件系統中,ACL分為兩個維度,一個是屬組,一個是權限,子目錄/文件默認繼承父目錄的ACL。而在Zookeeper中,node的ACL是沒有繼承關系的,是獨立控制的。Zookeeper的ACL,可以從三個維度來理解:一是scheme; 二是user; 三是permission,通常表示為

'scheme,'id
:permissions

下面從這三個方面分別來介紹:

scheme: scheme對應於采用哪種方案來進行權限管理,zookeeper實現了一個pluggable的ACL方案,可以通過擴展scheme,來擴展ACL的機制。zookeeper-3.4.4缺省支持下面幾種scheme:

  • world: 它下面只有一個id, 叫anyone, world:anyone代表任何人,zookeeper中對所有人有權限的結點就是屬於world:anyone的
  • auth: 它不需要id, 只要是通過authentication的user都有權限(zookeeper支持通過kerberos來進行authencation, 也支持username/password形式的authentication)
  • digest: 它對應的id為username:BASE64(SHA1(password)),它需要先通過username:password形式的authentication
  • ip: 它對應的id為客戶機的IP地址,設置的時候可以設置一個ip段,比如ip:192.168.1.0/16, 表示匹配前16個bit的IP段
  • super: 在這種scheme情況下,對應的id擁有超級權限,可以做任何事情(cdrwa)

permission: zookeeper目前支持下面一些權限:

  • CREATE(c): 創建權限,可以在在當前node下創建child node
  • DELETE(d): 刪除權限,可以刪除當前的node
  • READ(r): 讀權限,可以獲取當前node的數據,可以list當前node所有的child nodes
  • WRITE(w): 寫權限,可以向當前node寫數據
  • ADMIN(a): 管理權限,可以設置當前node的permission

3.1IP白名單模式授權

進入到zk目錄

cd /opt/cloudera/parcels/CDH/lib/zookeeper/bin

進入zk客戶端

./zkCli.sh -server xxx.xxx.xxx.xxx:2181

對需要進行白名單設置的路徑進行設置,此處設置的路徑沒有繼承關系,即設置了/test的白名單,但是/test/test2依然沒有設置為白名單。

setAcl /test ip:127.0.0.1:cdrwa

多個ip之間用逗號隔開,如:

setAcl /test ip:127.0.0.1:cdrwa,ip:192.168.10.3:cdrwa

通過此IP白名單設置之后,即只允許設定過的IP服務器才能進行訪問,其他機器無法訪問。

3.2auth模式授權

3.2.1添加用戶

addauth digest ramboo:ramboo

可以添加多個用戶,如

addauth digest ramboo1:ramboo1
addauth digest ramboo2:ramboo2
addauth digest ramboo3:ramboo3

3.2.2設置Acl權限

此處假如對/auth路徑進行設置,則

setAcl /auth auth:ramboo1:ramboo1:cdrwa

注:此處雖然設置了ramboo1用戶的權限,但是zk會默認添加所有存在的用戶。此處需要注意。

3.2.3查看Acl權限

getAcl /auth

結果如下所示:

'digest,'ramboo1:JXpHVJcEMUsIf5MM6u7TlOp3pqo=
: cdrwa
'digest,'ramboo2:lTTHGKOT6A3iEwj/SV5meGTXbAM=
: cdrwa
'digest,'ramboo3:b8+HkvFoPszTILQTMB1YFQ+Yvus=
: cdrwa

注:如果退出了客戶端,再進入的時候,需要重新添加用戶,才可訪問,即授權。

3.3digest模式授權

此模式,和auth模式的區別在於:

1、digest設置Acl的時候,可以不用先添加用戶,而auth設置Acl的時候,是需要提前設置用戶的,否則報錯。
2、digest設置的密碼要用密文,auth設置的密碼是明文。
3、auth設置的,只需設置一個用戶,就可以把所有用戶設置進去,而digest不行,只能對本次設置的用戶有效。也就是auth模式忽略id。

3.3.1生成密文密碼

在Linux下執行如下命令

echo -n xing:xing | openssl dgst -binary -sha1 | openssl base64

結果為:

kgk4DGva6vqOBYMGbMsXBZuFCXE=

3.3.2設置Acl權限

此處假如對/digest路徑進行設置,則

setAcl /digest digest:xing:kgk4DGva6vqOBYMGbMsXBZuFCXE=:cdrwa

#添加多個用戶,則用逗號隔開
  setAcl /digest digest:xing:kgk4DGva6vqOBYMGbMsXBZuFCXE=:cdrwa,digest:hang:YQRsX4vWAT6BHGo7yQi6tFSYxKc=:cdrwa
 

注:此處的密文密碼不要隨意更改,否則不知道對應的明文是多少,后續就沒辦法訪問對應節點,切記!

注:此處的密文密碼不要隨意更改,否則不知道對應的明文是多少,后續就沒辦法訪問對應節點,切記!

注:此處的密文密碼不要隨意更改,否則不知道對應的明文是多少,后續就沒辦法訪問對應節點,切記!

3.3.3查看Acl權限

此時如果沒有添加xing這個用戶,需要先添加,才可查看。添加命令如下:

addauth digest xing:xing

添加后,可查看:

getAcl /digest

結果為:

'digest,'xing:kgk4DGva6vqOBYMGbMsXBZuFCXE=
: cdrwa

4.忘記密碼修復方式

如果對上述設置授權后,忘記密碼了,怎么辦?方法如下:

  • 進入配置文件zoo.cfg,修改配置,設置跳過Acl驗證,配置如下:
skipACL=yes
  • 重啟zookeeper
  • 啟動后,可按照第一節所述的方式,重新進行Acl設置即可

5.利用zookeeper api進行zk實例的初始化和權限添加

代碼示例

    //給密碼加密
    public String getDigestUserPswd(String idPassword) throws NoSuchAlgorithmException {
        return DigestAuthenticationProvider.generateDigest(idPassword);
    }

    //獲取ACL列表,這里只設置一個可訪問用戶,用戶名為user,密碼為pswd。如果你需要多個,繼續add即可。
    public List<ACL> getAclList() {
        String idPassword = "user:pswd";
        if (idPassword == null) {
            logger.warn("no digest config,so use world scheme");
            return ZooDefs.Ids.OPEN_ACL_UNSAFE;
        }
        List<ACL> aclList = new ArrayList<>();
        try {
            Id zkUser = new Id("digest", getDigestUserPswd(idPassword));
            ACL acl = new ACL(ZooDefs.Perms.ALL, zkUser);
            aclList.add(acl);
        } catch (NoSuchAlgorithmException e) {
            logger.error(e);
        }
        return aclList;
    }

    //給znode設置權限,只有aclList的用戶可以訪問
    public void addDigestScheme() {
        zk.setACL(znode, aclList, -1);
    }

    //如何訪問加密的znode
    public void client() {
        ZooKeeper zk = new ZooKeeper(xxx);
        zk.addAuthInfo("digest", "user:pswd".getBytes());
    }

上面的代碼僅說明了核心步驟。

6.漏洞掃描驗證

上面我們在創建znode的時候進行了加密,這樣總可以通過漏洞掃描了吧。
重點來了。

但是如果你使用漏洞掃描工具掃描的話,還是有未授權訪問漏洞的,為啥呢?
不知道你有沒有注意,zk服務端啟動后,默認會啟動這幾個具有world和cdrwa權限的znode,“/” "/zookeeper" "/zookeeper/config"和"/zookeeper/quota"(根據zookeeper的版本不同可能存在不同,並且這幾個節點雖然具有world和cdrwa權限,但是是無法刪除的,不知道為什么,好在我們可以給它設置ACL列表。另外,官網對着幾個節點也沒有特別說明,估計和zk本身的一些配置相關吧,不刪除最好)。就是這幾個znode,會導致你的產品無法通過安全工具的漏洞掃描,你說坑不坑,解決辦法也是很簡單的,用我們前面說過的zk.setACL為這幾個節點設置權限就OK了,千萬別忘記根節點"/"了。

好了,到這里,才是真正的解決了這個未授權訪問漏洞問題了。

建議:如果zookeeper安裝在阿里雲服務器上的話,可以忽略此漏洞,通過安全組進行權限訪問。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM