歡迎您光臨本站 註冊首頁

囚禁你的精靈(daemon)進程

←手機掃碼閱讀     火星人 @ 2014-03-12 , reply:0
  來源:http://www.sans.org

作者:Matt Borland
翻譯:nixe0n


簡介
chroot牢籠(jail)概念綜述
Postfix精靈進程分析
一個禁錮(jail)HOWTO:icecast



第一步:把icecast安裝在牢籠(jail)環境中
第二步:配置牢籠(jail)環境
第三步:為這個精靈建立一個chroot包裝


那些地方不能用牢籠環境
結論



簡介


我們經常會聽說計算機遭到基於Internet的遠程攻擊。通常位於攻擊最前線的是一些伺服器軟體,例如:WEB、郵件和DNS,這些服務通常是通過監控進程(daemon,也可以叫作精靈進程)來提供的。這些服務即使是位於防火牆之後,也需要面對各種探測和攻擊,以至讓攻擊者獲得系統訪問許可權。大多數的惡意攻擊者都會在系統安裝rootkit,以便能夠進行通常的系統操作。

一般情況下,這些rootkit和病毒需要使用目標系統的可執行文件、動態連接庫以及配置文件。比如:一個安裝在linux主機上的rootkit可能需要訪問/bin/sh或者能夠讀寫/etc目錄下的系統配置文件。而且一旦系統被攻擊者侵入,攻擊者獲得了root許可權,就可以運行修改任何自己需要的文件。最近的lion、ramen蠕蟲對BIND的攻擊就可以證明以上觀點。

但是如果你對精靈進程(daemon)進行限制,只允許其訪問必要的文件,而不能訪問整個文件系統,又將如何呢?這樣就可以使我們的安全不再依賴於daemon軟體開發人員的安全水平。

幸運的是,UNIX系統能夠提供這樣一種機制實現上面這種想法。在最近的BIND攻擊中,Thaumaturgix, Inc的IT管理員William Cox提出了「在chrooted的環境中運行伺服器進程,減小你的暴露程度(The best way to limit your exposure is to run the server in a 'chrooted' environment))。這種chrooted環境通常叫作一個chroot牢籠(jail),實際上這種概念已經存在了很長時間了,但是一直沒有被軟體開發人員和系統管理人員充分利用。



chroot牢籠(jail)概念綜述


實現一個chroot jail包括兩種方式:



限制進程只能訪問整個文件系統的一個子集。


以較低的許可權運行服務進程。


這兩種方式是由一些標準的系統調用來提供的。首先,是chroot(),這個系統調用能夠限制進程對文件系統的訪問。即使某個進程是以root的許可權運行的,它對文件/目錄的訪問也都是相對於chroot()系統調用限制的整個文件系統的子目錄。

例如,如果一個進程以/var/sample/jail為參數執行了chroot()系統調用,現在它要訪問一個文件:/etc/passwd,但是操作系統最後會把這個訪問請求替換為對 /var/sample/jail/etc/passwd的訪問。chroot系統調用只能以root許可權調用。

降低進程許可權的系統調用主要包括:setuid()、setgid()和setgroups()。setuid()指定進程的實際和有效用戶許可權;而setgid()指定進程的實際和有效組許可權。setuid()系統非常重要,一旦通過它進入較低的許可權運行,進程將無法自己重新獲得root許可權。setgroups()定義進程的追加組成員關係。除此之外,還有一些其它的相關係統調用,用戶可以從自己系統的手冊頁中獲得相關文檔。

其它種類的操作系統可能還有另外的進程束縛方法。例如在FreeBSD中就有一個jail()函數。為了使你更好地體會到jailing的好處,我將通過一個典型的rootkit加以說明,在不同的許可權下以及有沒有被限制在jail環境中rootkit對系統的危害是不同的。在此,要時刻記住一件事情,當一個服務被侵入,攻擊者就能夠擁有服務進程所具有的許可權。請看下面這個表格:


+-----------------+---------------------------------------\
| | | |
| | running as root | running non-root |
| | | |
+-----------------+-------------------+-------------------|
| | | |
| entire fs | (a) | (c) |
| | | |
|-----------------+-------------------+-------------------|
| | | |
| jailed fs | (b) | (d) |
| | | |
+---------------------------------------------------------/





運行於(a)類(進程以root許可權運行並且可以訪問整個文件系統)狀態下的進程是rootkit的首選目標,侵入這樣的服務,攻擊者可以修改二進位可執行文件,例如:/bin/ps、/bin/netstat等,打開特權網路埠,讀取任意的系統文件包括:/etc/shadow文件。最糟糕的是,他們能夠對系統進行完全的破壞,比如:rm -rf /。運行於這種狀態,最為常見的一個例子就是sendmail(http://www.sendmail.org。


如果服務進程處於(b)類(root許可權、牢籠環境)狀態下,一般的rootkit就可能無法正常操作,因為它們一般需要一個shell(/bin/sh)和一些基本的命令,例如:/bin/rm和/bin/cp。然而,在這種狀態下,rootkit照樣可以打破牢籠(jail)。因為服務進程以root許可權運行,攻擊者可以通過攻擊代碼直接執行一些允許root執行的操作(例如:直接引用牢籠之外文件系統的索引節點)。因此,這種狀態雖然比(a)類狀態安全(門檻高的多),但是也無法對服務提供足夠的保護。


服務進程處於(c)類(非root許可權,可以訪問整個文件系統)狀態下,對整個系統的威脅比(a)狀態小,因為畢竟攻擊者無法直接獲得root許可權。但是,如果服務進程處於這種狀態下,攻擊者一旦侵入這個服務,就可以執行一些命令,獲得一個shell進行交互,然後很可能通過本地攻擊獲得root許可權。即使攻擊者不能獲得root許可權,也可以訪問到系統的絕大多數配置文件和其它信息,例如:用戶的電子郵件帳戶信息(大量的垃圾郵件將蜂擁而至)。


最後,處於(d)類(非root許可權,jail環境)狀態下的服務進程受到的限制最為苛刻,這樣攻擊者根本沒有機會執行shell,也不可能獲得大量的系統信息。而且,對系統進行的所有破壞都被限制在jail環境中。在這種狀態下,最大的威脅就是攻擊者在這個jail環境中防止一個可以被jail環境之外的進程訪問的可執行文件,從而使攻擊代碼擴散出jail環境。因此,你應該經常監視你的牢籠,看一下裡面的囚犯是否逃出來了:P。


下面我們將舉一個現實的例子進行說明。



Postfix精靈進程分析


Postfix(http://www.postfix.org)是一個郵件傳輸代理(Mail Transfer Agent)。它允許用戶收/發SMTP郵件,把給本地用戶的郵件投遞到用戶主機。Postfix是sendmail的一個變通,作者Wietse Venema對安全問題傾注了很大的關注。這個軟體是一個非常典型的所謂守紀律精靈(disciplined daemon),可以安裝在一個chroot牢籠(jail)環境中。我相信理解了Postfix是如何工作的,你就可以實現一個簡單的安全精靈(daemon)。

Postfix從一個叫作master的程序開始執行,master以root許可權啟動,然後繼續以root許可權運行。不過,master本身非常小,其作用這是spawn進程,這些進程大部分會被放在一個chroot牢籠(jail)環境中執行實際的工作。通過這種方式,以root許可權運行的代碼數量非常有限。

下面我們看一看master是怎樣和smtpd進行交互的。master一旦檢測到一個向25號埠(SMTP的監聽埠)的連接,它就會執行smtpd。下面我們就看一下postfix使用的一些jailing方法,這些代碼在src/util/chroot_uid.c文件中。在講述過程中,我們把/var/spool/postfix作為chroot牢籠(jail)環境的根目錄:


+-----------------------------+-----------------+--------------------\
| | user/group | filesystem |
+-----------------------------+-----------------+--------------------|
| master is run on startup | root/root | / |
|-----------------------------+-----------------+--------------------|
| master opens port 25 | root/root | / |
|-----------------------------+-----------------+--------------------|
| master detects connection | root/root | / |
|-----------------------------+-----------------+--------------------|
| master forks smtpd | root/root | / |
|-----------------------------+-----------------+--------------------|
| master continues execution | root/root | / |
|-----------------------------+-----------------+--------------------|
| smtpd inherits permissions | root/root | / |
|-----------------------------+-----------------+--------------------|
| smptd calls setgid() | root/postfix | / |
|-----------------------------+-----------------+--------------------|
| smptd calls initgroups()* | root/postfix | / |
|-----------------------------+-----------------+--------------------|
| smtpd calls chroot() | root/postfix | /var/spool/postfix |
|-----------------------------+-----------------+--------------------|
| smptd calls setuid() | postfix/postfix | /var/spool/postfix |
|-----------------------------+-----------------+--------------------|
| smtpd processes connection | postfix/postfix | /var/spool/postfix |
|-----------------------------+-----------------+--------------------|
| smtpd continues listening | postfix/postfix | /var/spool/postfix |
+-----------------------------+-----------------+--------------------/
* initgroups()類似於setgroups();設置多重組成員關係。


最後,smtpd進程的狀態如下所示(503是postfix用戶/組的ID):


#cat /proc/status

Name: smtpd
State: S (sleeping)
Pid: 1301
PPid: 665
TracerPid: 0
Uid: 503 503 503 503
Gid: 503 503 503 503
FDSize: 256
Groups: 503
[...]


處理完這個連接后,smtpd精靈會繼續監聽SMTP連接,如果在指定的時間內沒有連接,就超時退出。

從上面的過程你可以對進程狀態的演變有一個大體的了解。在整個生命周期中,smtpd從(a)狀態開始,接著進入(b)狀態,然後快速地進入(d)狀態,最後在(d)狀態中運行。實際上,這是把進程放到正確的chroot牢籠(jail)環境的標準步驟。



一個jail HOWTO:icecast


理解了這些背景知識非常有用,但是怎樣對一個精靈進程進行禁錮?而且,對一個精靈進程進行禁錮,是否還要取決於精靈進程本身是否願意?為了回答這些問題,我將講述一個實際的精靈禁錮過程,雖然它比較簡單,但是其作者並沒有給出一個精靈禁錮文檔。不過請注意:一些流行的精靈系統例如:BIND,已經有了如何創建一個chroot牢籠環境的文檔。

在我們的例子中,我選擇的程序叫作icecast(http://www.icecast.org)。icecast是一個音頻流中繼伺服器,它從一個基於網路的客戶程序(例如:winamp)獲得音頻流,然後接收一定數量聽眾的連接,讓這些聽眾收聽連續的音頻流。我想在自己的機器上運行這個程序,但是我恐怕這個服務程序存在安全缺陷,所以想對其進行限制。

我們看一下這個服務起始的許可權,3這個精靈進程打開兩個不需root許可權的埠,一個用於接收音頻流,而另一個等待客戶程序的連接。在運行過程中,還可以通過一個本地控制台對其進行維護,不過這不是必須的。除此之外,在運行過程中icecast還要維護一個日誌文件。

這個程序以非root許可權運行,這很好。但是,如果不對其進行禁錮(jail),在理論上如果它被攻擊者侵入,讓攻擊者獲得了一個shell,攻擊者就可以窺探我的系統,甚至通過其它的本地攻擊獲得root許可權。因此,我要對icecast進行禁錮(jail)。

下面是我們的禁錮過程:



把這個精靈安裝到指定的目錄,在保證它能夠正常運行的情況下,為其分配儘可能小的文件訪問許可權。把所有不必要的東西從這個牢籠(jail)目錄刪除。


對這個牢籠環境進行必要的配置。這個環境一般包括:精靈運行的動態連接庫文件,一個本地的/dev/null設備,可能還需要一些本地的時間信息。


如果必要,還要建立一個執行chroot和放棄教高許可權的函數包裝(wrapper)。如果這個精靈能夠想postfix的子進程那樣自己實現上述功能,你就可以不必自己來做了。要注意:一定要把這些包裝(wrapper)放在牢籠(jail)環境之外。


第一步:把icecast安裝在牢籠(jail)環境中

首先,我們把所有icecast的文件安裝到/usr/local/icecast目錄,在我們的例子中,/usr/local/icecast是icecast牢籠(jail)的根目錄。你安裝牢籠(jail)環境的地方非常重要,可能應該是一個只讀的文件系統。

下面是其安裝目錄的內容,icecast安裝目錄的所有者是root


drwxr-xr-x 2 root root 4096 May 6 14:38 bin
drwxr-xr-x 2 root root 4096 May 19 18:43 conf
drwxr-xr-x 2 root root 4096 May 6 14:38 doc
drwxr-xr-x 2 root root 4096 May 6 14:41 logs
drwxr-xr-x 2 root root 4096 May 19 16:41 static
drwxr-xr-x 2 root root 4096 May 6 14:38 templates


功過閱讀icecast的文檔和一些實驗,我們知道icecast正常運行需要以下的文件/目錄許可權:


可執行:bin/icecast
可寫:logs目錄
可讀:conf、static和templates目錄


現在,我決定建立一個叫icecast的用戶,使用這個用戶來運行icecast。在執行這個服務時,需要向logs目錄中寫入日誌,而我又不想讓任何人都能夠寫這個目錄,因此才建立這個新的用戶。


#useradd icecast -s /bin/false


然後,你應該在/etc/passwd中發現如下條目,而且這個帳戶處於鎖定狀態,無法登錄:


icecast:x:505:505::/usr/local/icecast:/bin/false


現在,我們需要決定需要那些文件以及它們應該放在哪裡。首先,我們需要改變logs子目錄的許可權,還可以把沒有必要的子目錄doc刪除。

icecast不象postfix的子進程,能夠自己調用chroot系統調用,因此為了在執行chroot包裝(wrapper)程序之後,能夠執行icecast,我們需要把bin/icecast可執行文件放在這個牢籠(jail)環境中。然後,我們需要編寫一個chroot包裝程序,把他放在牢籠(jail)環境之外。

除此之外,icecast還需要在conf目錄配置文件。我們假設icecast已經被安裝在/usr/local/icecast目錄中。


第二步:配置牢籠(jail)環境

這一步的目標是找出icecast運行需要的動態連接庫並把它們安裝到這個牢籠(jail)環境,這一部分可能因系統而異。沒有這些動態連接庫,icecast將無法執行,而且這個原因顯示的執行錯誤信息也讓人摸不著頭腦,比如:/bin/icecast: File Not Found

在Linux系統中,你可以運行ldd程序來查看icecast需要的動態連接庫以及它們在文件系統的位置。例如(所有的命令我們都是在/usr/local/icecast目錄下執行的):


$ ldd bin/icecast
libm.so.6 => /lib/i686/libm.so.6 (0x40022000)
libpthread.so.0 => /lib/i686/libpthread.so.0 (0x40046000)
libc.so.6 => /lib/i686/libc.so.6 (0x4005b000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)


現在,我們把這些動態連接庫都複製到這個牢籠(jail)的相似位置:


# mkdir -p lib/i686
# cp -pi /lib/i686/libm.so.6 /lib/i686/libpthread.so.0 /lib/i686/libc.so.6 lib/i686
# cp -pi /lib/ld-linux.so.2 lib


這樣,這些動態連接庫就被複制到了牢籠(jail)的/lib目錄下,也就是說bin/icecast能夠在牢籠中執行了。

不過,這樣還不夠,在任何的牢籠環境中都建立一個/dev/null設備是一個非常不錯的想法:


# mkdir dev
# mknod -m 666 dev/null c 1 3


這一步要謹慎,並確信你已經正確地建立了設備節點。

許多服務可能需要系統的/etc/localtime文件。最後,我們需要把/etc/localtime文件複製到/usr/local/icecast/etc/目錄中,並填加一個到/usr/local/icecast/usr/lib/zoneinfo的符號連接:


# mkdir etc
# mkdir usr/lib
# cp /etc/localtime etc
# ln -s /etc/localtime usr/lib/zoneinfo


現在,我們為icecast精靈準備的牢房已經裝修的差不多了,裡面有如下目錄:


drwxr-xr-x 2 root root 4096 May 6 14:38 bin
drwxr-xr-x 2 root root 4096 May 19 18:43 conf
drwxr-xr-x 2 root root 4096 May 19 18:01 dev
drwxr-xr-x 2 root root 4096 May 6 14:38 doc
drwxr-xr-x 2 root root 4096 May 22 14:41 etc
drwxr-xr-x 2 root root 4096 May 19 15:30 lib
drwxr-xr-x 2 icecast icecast 4096 May 6 14:41 logs
drwxr-xr-x 2 root root 4096 May 19 16:41 static
drwxr-xr-x 2 root root 4096 May 6 14:38 templates
drwxr-xr-x 3 root root 4096 May 22 14:42 usr


第三步:為這個精靈建立一個chroot包裝

記住:執行chroot需要root許可權。

你可能會想,我首先執行/usr/sbin/chroot,然後執行/bin/su,接著執行/bin/icecast,就能夠把icecast精靈放到牢籠環境。但是別忘了,一旦執行了/usr/sbin/chroot,你就不能再訪問整個文件系統了,也就是你將無法執行su程序了。把su也放到這個牢籠環境中也是可以的,但是其關聯文件非常複雜,很難維護,而且su是一個SUID程序,放到了這個環境中,肯定會降低這個環境的安全性。

編寫一個簡短的C程序,通過這個程序調用必要的jail系統調用,然後執行icecast服務,是一個比較容易的解決方案。這個程序將在這個牢籠之外執行,它需要做以下事情:



執行chroot系統調用,進入牢籠。


把組識別符和組成員關係設置為icecast。


把用戶識別符設置為icecast。


執行/bin/icecast。


有一點要注意:這個程序的許可權不能設置setuid/setgid位。我們的目的是以超級用戶的許可權調用setuid()/setgid()系統調用降低系統的許可權,和把程序的許可權設置為SUID或者SGID有極大的差別。把程序的SUID/SGID置位表示程序以擁有者的許可權運行,通常意味著提高程序運行的許可權。

下面我提供一個簡化的chroot包裝程序。請注意:在實際過程中應該注意對每個系統調用錯誤的處理。


=================================================
#include
#include

main (argc, argv) {

int gidlist[] = {505};

chroot("/usr/local/icecast");
chdir("/");

setgid(505);
setgroups(1,gidlist); // also, could use initgroups

setuid(505);

execl("/bin/icecast","/bin/icecast",NULL);

}
==================================================


這裡也要注意,不要把這個程序放在後台執行。在這個例子中,我只要修改icecast的配置文件就能夠使icecast在後台運行。

現在我們的牢籠已經做好了,只要執行以上的包裝程序,就可以把icecast囚禁到裡面了:P。上面的包裝程序你可以放在任何自己喜歡的位置,只是不要放在/usr/local/icecast目錄下就可以了。你也可以在自動啟動腳本中加入這個包裝程序,以便icecast能夠在系統啟動是自動運行。



那些地方不能用牢籠環境


有些情況下,不太可能實現對精靈進程的禁錮管理。

讓我們看一下apache WEB伺服器。apache的開發者在開發這個軟體時就非常注意其安全問題,httpd進程通常以root許可權啟動,然後其派生出來的進程都是在比較低的許可權(通常是nobody)下處理運行的,就象master/smtpd之間的關係。也就是說,處理客戶請求的httpd進程是在c類狀態下運行的。

雖然你也可以禁錮Apache WEB伺服器,但是在某些情況下,這項工作幾乎是無法完成的。例如:在WEB伺服器中,你使用了PHP模塊,PHP模塊的特徵極為豐富,其動態連接庫極為繁雜,在這種情況下,創建一個牢籠環境就有些得不償失了。

還有一種情況就是如果精靈進程確實需要對這個文件系統的訪問許可權,例如postfix的某些組件確實需要root許可權把郵件投遞到用戶的目錄。



結論


我發現很少有人對實現一個chroot牢籠環境傾注注意力,希望通過這篇文章能夠讓大家知道禁錮精靈進程的好處,並對大家自己實現牢籠環境有所幫助。


參考:


(1) Fearnow, Matt. "Lion Worm." SANS Global Incident Analysis Center, April 2001.
http://www.sans.org/y2k/lion.htm

(2) Radcliff, Deborah. "Stuck in a BIND" Computerworld, February 2001.
http://www.itworld.com/Net/4055/CWSTO57547

(3) FreeBSD, Inc. "jail() man page" April 1999.
http://www.freebsd.org/cgi/man.cgi?query=jail&sektion=2&apropos=0&manpath=FreeBSD+4.0-RELEASE

(4) Burr, Simon. "How to break out of a chroot() jail." January 2001.
http://www.bpfh.net/simes/computing/chroot-break.html

(5) Wunsch, Scott "Chroot-BIND HOWTO" Linux Documentation Project, September 2000.
http://www.linuxdoc.org/HOWTO/Chroot-BIND-HOWTO.html

(6) Deatrich, Denice. "How to 'chroot' an Apache tree with Linux and Solaris." February 2001.
http://penguin.epfl.ch/chroot.html

Moen, Rick "Attacking Linux" LinuxWorld.com, August 29 2000.
http://www.itworld.com/Sec/2199/LWD000829hacking/

Fennelly, Carole "Real Hackers go to Usenix" Unix Insider, November 17 2000
http://www.itworld.com/Sec/2052/UIR001117security/

Brumley, David. "invisible intruders: rootkits in practice" Usenix, November 1999.
http://www.usenix.org/publications/login/1999-9/features/rootkits.html

Miller, Toby. "Analysis of the T0rn rootkit" GIAC, 2000. http://www.sans.org/y2k/t0rn.htm


[火星人 ] 囚禁你的精靈(daemon)進程已經有525次圍觀

http://coctec.com/docs/program/show-post-72132.html