用capability 特徵加強Linux系統安全(轉)

BSDLite發表於2007-08-16
用capability 特徵加強Linux系統安全(轉)[@more@]  本文僅做參考學習

  摘要:傳統UNIX系統的訪問控制模型非常簡單——普通使用者對超級使用者。在這種模型中,一個程式或者帳戶要麼只有很小的許可權,要麼具有全部的系統許可權。顯然,這樣對系統的安全沒有什麼好處。從Linux-2.1核心開始,引入了能力(capability)的概念,實現了更細粒度的訪問控制。

   1.簡介

   UNIX是一種安全作業系統,它給普通使用者儘可能低的許可權,而把全部的系統許可權賦予一個單一的帳戶——root.root帳戶用來管理系統、安裝軟體、管理帳戶、執行某些服務、安裝/解除安裝檔案系統、管理使用者、安裝軟體等。另外,普通使用者的很多操作也需要root許可權,這透過setuid實現。

   這種依賴單一帳戶執行特權操作的方式加大了系統的面臨風險,而需要root許可權的程式可能只是為了一個單一的操作,例如:繫結到特權埠、開啟一個只有root許可權可以訪問的檔案。某些程式可能有安全漏洞,而如果程式不是以root的許可權執行,其存在的漏洞就不可能對系統造成什麼威脅。

   從2.1版開始,核心開發人員在Linux核心中加入了能力(capability)的概念。其目標是消除需要執行某些操作的程式對root帳戶的依賴。從2.2版本的核心開始,這些代基本可以使用了,雖然還存在一些問題,但是方向是正確的。

   2.Linux核心能力詳解

   傳統UNIX的信任狀模型非常簡單,就是“超級使用者對普通使用者”模型。在這種模型中,一個程式要麼什麼都能做,要麼幾乎什麼也不能做,這取決於程式的UID.如果一個程式需要執行繫結到私有埠、載入/解除安裝核心模組以及管理檔案系統等操作時,就需要完全的root許可權。很顯然這樣做對系統安全存在很大的威脅。UNIX系統中的SUID問題就是由這種信任狀模型造成的。例如,一個普通使用者需要使用ping命令。這是一個SUID命令,會以root的許可權執行。而實際上這個程式只是需要RAW套接字建立必要ICMP資料包,除此之外的其它root許可權對這個程式都是沒有必要的。如果程式編寫不好,就可能被攻擊者利用,獲得系統的控制權。

   使用能力(capability)可以減小這種風險。系統管理員為了系統的安全可以剝奪root使用者的能力,這樣即使root使用者也將無法進行某些操作。而這個過程又是不可逆的,也就是說如果一種能力被刪除,除非重新啟動系統,否則即使root使用者也無法重新新增被刪除的能力。

   2.1.能力的概念

   Linux核心中使用的能力(capability)概念非常容易被混淆。電腦科學中定義了很多種能力(capability)。能力就是一個程式能夠對某個物件進行的操作,它標誌物件以及允許在這個物件上進行的操作。檔案描述符就是一種能力,你使用open系統呼叫請求獲得讀或者寫的許可權,如果open系統呼叫成功,系統的核心就會建立一個檔案描述符。然後,如果收到讀或者寫的請求,核心就使用這個檔案描述符作為一個資料結構的索引,檢索相關的操作是否允許。這是一種檢查許可權的有效方式,在執行open系統呼叫是,核心一次性建立必要的資料結構,然後的讀寫等操作檢查只需要在資料結構中梭梭即可。對能力的操作包括:複製能力、程式間的遷移能力、修改一個能力以及撤消一個能力等。修改一個能力類似與把一個可以讀寫的檔案描述符改為只讀。目前,各種系統對能力的應用程度並不相同。

   POSIX 1003.1e中也提出了一種能力定義,通常稱為POSIX能力(POSIX capabilities),Linux中的定義不大一樣。核心使用這些能力分割root的許可權,因為傳統*NIX系統中root的許可權過於強大了。

   2.2.Linux是如何使用POSIX capabilities代替傳統的信任狀模型的

   每個程式有三個和能力有關的點陣圖:inheritable(I)、permitted(P)和effective(E),對應程式描述符task_struct(include/linux/sched.h)裡面的cap_effective, cap_inheritable, cap_permitted.每種能力由一位表示,1表示具有某種能力,0表示沒有。當一個程式要進行某個特權操作時,作業系統會檢查cap_effective的對應位是否有效,而不再是檢查程式的有效UID是否為0.例如,如果一個程式要設定系統的時鐘,Linux的核心就會檢查cap_effective的CAP_SYS_TIME位(第25位)是否有效,

   cap_permitted表示程式能夠使用的能力。在cap_permitted中可以包含cap_effective中沒有的能力,這些能力是被程式自己臨時放棄的,也可以說cap_effective是cap_permitted的一個子集。程式放棄沒有必要的能力對於提高安全性大有助益。例如,ping只需要CAP_NET_RAW,如果它放棄除這個能力之外的其它能力,即使存在安全缺陷,也不會對系統造成太大的損害。cap_inheritable表示能夠被當前程式執行的程式繼承的能力。

   3.Linux支援的能力

   Linux實現了7個POSIX 1003.1e規定的能力,還有21個(截止到2.4.7-10版本的核心)Linux所特有的,這些能力在/usr/src/linux/include/linux/capability.h檔案中定義。其細節如下:

   能力名 數字 描述CAP_CHOWN 0 允許改變檔案的所有權CAP_DAC_OVERRIDE

  1 忽略對檔案的所有DAC訪問限制CAP_DAC_READ_SEARCH
  2 忽略所有對讀、搜尋操作的限制CAP_FOWNER
  3 如果檔案屬於程式的UID,就取消對檔案的限制CAP_FSETID
  4 允許設定setuid位CAP_KILL
  5 允許對不屬於自己的程式傳送訊號CAP_SETGID
  6 允許改變組ID CAP_SETUID
  7 允許改變使用者ID CAP_SETPCAP
  8 允許向其它程式轉移能力以及刪除其它程式的任意能力CAP_LINUX_IMMUTABLE
  9 允許修改檔案的不可修改(IMMUTABLE)和只新增(APPEND-ONLY)屬性CAP_NET_BIND_SERVICE
  10 允許繫結到小於1024的埠CAP_NET_BROADCAST
  11 允許網路廣播和多播訪問CAP_NET_ADMIN
  12 允許執行網路管理任務:介面、防火牆和路由等,詳情請參考/usr/src/linux/include/linux/capability.h檔案CAP_NET_RAW
  13 允許使用原始(raw)套接字CAP_IPC_LOCK
  14 允許鎖定共享記憶體片段CAP_IPC_OWNER
  15 忽略IPC所有權檢查CAP_SYS_MODULE
  16 插入和刪除核心模組CAP_SYS_RAWIO
  17 允許對ioperm/iopl的訪問CAP_SYS_CHROOT
  18 允許使用chroot()系統呼叫CAP_SYS_PTRACE
  19 允許跟蹤任何程式CAP_SYS_PACCT
  20 允許配置程式記帳(process accounting)

   CAP_SYS_ADMIN 21 允許執行系統管理任務:載入/解除安裝檔案系統、設定磁碟配額、開/關交換裝置和檔案等。詳情請參考/usr/src/linux/include/linux/capability.h檔案。

   CAP_SYS_BOOT 22 允許重新啟動系統CAP_SYS_NICE 23 允許提升優先順序,設定其它程式的優先順序CAP_SYS_RESOURCE 24 忽略資源限制CAP_SYS_TIME 25 允許改變系統時鐘CAP_SYS_TTY_CONFIG 26 允許配置TTY裝置CAP_MKNOD 27 允許使用mknod()系統呼叫CAP_LEASE 28 Allow taking of leases on files

   4.能力邊界集

   Linux2.2核心提供了對能力的基本支援。但是在引入了能力之後遇到了一些困難,雖然2.2版本的核心能夠理解能力,但是缺乏一個系統和使用者之間的介面。除此之外,還存在其它的一些問題。從2.2.11版本開始,這種情況發生了很大的改觀,在這個版本中引入了能力邊界集(capability bounding set)的概念,解決了和系統和使用者之間的介面問題。能力邊界集(capability bounding set)是系統中所有程式允許保留的能力。如果在能力邊界集中不存在某個能力,那麼系統中的所有程式都沒有這個能力,即使以超級使用者許可權執行的程式也一樣。

   能力邊界集透過sysctl命令匯出,使用者可以在/proc/sys/kernel/cap-bound中看到系統保留的能力。在預設情況下,能力邊界集所有的位都是開啟的。

   root使用者可以向能力邊界集中寫入新的值來修改系統保留的能力。但是要注意,root使用者能夠從能力邊界集中刪除能力,卻不能再恢復被刪除的能力,只有init程式能夠新增能力。通常,一個能力如果從能力邊界集中被刪除,只有系統重新啟動才能恢復。

   刪除系統中多餘的能力對提高系統的安全性是很有好處的。假設你有一臺重要的伺服器,比較擔心可載入核心模組的安全性。而你又不想完全禁止在系統中使用可載入核心模組或者一些裝置的驅動就是一些核心模組。在這種情況下,最好使系統在啟動時載入所有的模組,然後禁止載入/解除安裝任何核心模組。在Linux系統中,載入/解除安裝核心模組是由CAP_SYS_MODULE能力控制的。如果把CAP_SYS_MODULE從能力邊界集中刪除,系統將不再允許載入/解除安裝任何的核心模組。

   CAP_SYS_MODULE能力的值是16,因此我們使用下面的命令就可以把它從能力邊界集中刪除:

   echo 0xFFFEFFFF >/proc/sys/kernel/cap-bound

   5.lcap

   雖然我們可以直接修改/proc/sys/kernel/cap-bound來刪除系統的某中能力,但是這樣畢竟非常的不方便。有一個程式lcap可以幫助我們更方便的從系統中刪除指定的能力。它可以從下載。編譯之後就可以直接使用。如果不帶引數,lcap可以列出系統當前支援的各種能力:

   [root@nixe0n lcap-0.0.6]# ./lcap Current capabilities: 0xFFFFFEFF 0) *CAP_CHOWN

  1) *CAP_DAC_OVERRIDE
  2) *CAP_DAC_READ_SEARCH
  3) *CAP_FOWNER
  4) *CAP_FSETID
  5) *CAP_KILL
  6) *CAP_SETGID
  7) *CAP_SETUID
  8) CAP_SETPCAP
  9) *CAP_LINUX_IMMUTABLE
  10) *CAP_NET_BIND_SERVICE
  11) *CAP_NET_BROADCAST
  12) *CAP_NET_ADMIN
  13) *CAP_NET_RAW
  14) *CAP_IPC_LOCK
  15) *CAP_IPC_OWNER
  16) *CAP_SYS_MODULE
  17) *CAP_SYS_RAWIO
  18) *CAP_SYS_CHROOT
  19) *CAP_SYS_PTRACE
  20) *CAP_SYS_PACCT
  21) *CAP_SYS_ADMIN
  22) *CAP_SYS_BOOT
  23) *CAP_SYS_NICE
  24) *CAP_SYS_RESOURCE
  25) *CAP_SYS_TIME
  26) *CAP_SYS_TTY_CONFIG * = Capabilities currently allowed

   如果我們需要刪除某個能力,直接把能力名作為引數就可以,例如我們要刪除載入/解除安裝核心模組的能力:

   [root@nixe0n lcap-0.0.6]# ./lcap CAP_SYS_MODULE

  [root@nixe0n lcap-0.0.6]# ./lcap Current capabilities: 0xFFFBFEFF

  0) *CAP_CHOWN
  1) *CAP_DAC_OVERRIDE
  2) *CAP_DAC_READ_SEARCH
  3) *CAP_FOWNER
  4) *CAP_FSETID
  5) *CAP_KILL
  6) *CAP_SETGID
  7) *CAP_SETUID
  8) CAP_SETPCAP
  9) *CAP_LINUX_IMMUTABLE
  10) *CAP_NET_BIND_SERVICE
  11) *CAP_NET_BROADCAST
  12) *CAP_NET_ADMIN
  13) *CAP_NET_RAW
  14) *CAP_IPC_LOCK
  15) *CAP_IPC_OWNER
  16) CAP_SYS_MODULE
  17) *CAP_SYS_RAWIO
  18) *CAP_SYS_CHROOT
  19) *CAP_SYS_PTRACE
  20) *CAP_SYS_PACCT
  21) *CAP_SYS_ADMIN
  22) *CAP_SYS_BOOT
  23) *CAP_SYS_NICE
  24) *CAP_SYS_RESOURCE
  25) *CAP_SYS_TIME
  26) *CAP_SYS_TTY_CONFIG * = Capabilities currently allowed

   6.能力邊界集的安全問題

   能力邊界集為系統和管理員之間提供了一個便利的互動介面,但是它存在一些的脆弱性。Patrick Reynolds在提交到BugTraq的一個郵件裡詳細分析了這種脆弱性。對能力邊界集的最大威脅就是能夠被讀/寫的/dev/mem裝置。在核心記憶體區中,/proc/sys/kernel/cap-bound直接影射到cap_bset變數中。如果/dev/mem可以寫,攻擊者就能夠直接修改記憶體重置cap_bset變數。從而能夠越過能力邊界集開啟所有的能力。使用以下命令就可以獲得cap_bset變數的地址:

   $ grep cap_bset System.map c01f0cd5 ? __kstrtab_cap_bset c01f7340 ? __ksymtab_cap_bset c01fb2ac D cap_bset

   從結果可以看出,cap_bset位於c01fb2ac.攻擊者獲得了/dev/mem的寫許可權,只要寫入0xffffffff就能夠重新開啟所有的能力。

   因此,為了維護能力邊界集的安全,你應該放棄系統的CAP_SYS_RAWIO能力。這樣會造成X系統和其它一些需要訪問/dev/mem或I/O埠的程式無法執行,不過對於伺服器來說,這是值得的。除了關閉CAP_SYS_RAWIO,還應該放棄CAP_SYS_MODULE能力。

   7.侷限

   雖然利用能力可已經以有效地保護系統的安全,但是由於檔案系統的制約,Linux的能力控制還不是很完善。我們除了可以使用lcap從總體上放棄一些能力之外,伺服器軟體程式設計師也應該主動放棄程式的一些多餘的能力。例如,xntpd程式可以透過以下的步驟放棄沒有必要的能力,以加強安全性:

   以完整的root許可權啟動繫結到ntp埠除了CAP_SYS_TIME能力之外,放棄其它的能力放棄root許可權以普通管理帳戶的身份進行正常的操作

   但是,並不是所有的程式設計師能夠注意到這個問題,如果能夠直接使用chmod和chattr命令限制程式的能力將給為方便。例如:

   [root@localhost /root]# chattr +CAP_BIND xntpd

   目前,由於檔案系統的制約,還無法實現。

   8.結論

   在本文,我們討論了Linux的能力,並說明了如何使用相關的工具加強系統的安全性。但是,能力還守制於檔案系統的擴充套件,並不是非常完善。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10617542/viewspace-962270/,如需轉載,請註明出處,否則將追究法律責任。

相關文章