分类: LINUX
2008-05-07 15:10:23
CHROOT就是Change Root,也就是改变程序执行时所参考的根目录位置。
一般的目录架构:
/
/bin
/sbin
/usr/bin
/home
CHROOT的目录架构:
/hell/
/hell/bin
/hell/usr/bin
/hell/home
* 为何要CHROOT?
1.限制被CHROOT的使用者所能执行的程序,如SetUid的程序,或是会造成
Load 的 Compiler等等。
2.防止使用者存取某些特定档案,如/etc/passwd。
3.防止入侵者/bin/rm -rf /。
4.提供Guest服务以及处罚不乖的使用者。
5.增进系统的安全。
* 要如何建立CHROOT的环境?
1.chroot()这个function:
chroot(PATH)这个function必须具有 root 的身份才能执行,执行后会
将跟目录切换到 PATH 所指定的地方。
2.login的过程:
使用者无论是从console或是telnet进入,都必须执行/usr/bin/login来
决定是否能进入系统,而login所做的动作大致是:
(1)印出login的提示符号,等待使用者输入密码。
(2)检查密码是否正确,错误的话回到(1)。
(3)正确的话以setuid()来改变身份为login_user。
(4)以exec()执行user的shell。
因此我们必须先修改/usr/bin/login的source code,让login在(2)到(3)
的中间执行chroot($CHROOT_PATH)的动作,已达到CHROOT的目的,并以修
改过的login替代原先的/usr/bin/login。
(5)稍微好一点的方法必须在做chroot()之前检查login
user的group,如果有某个特定的group(如chrootgrp)
才执行chroot(),不然所有的人都会被chroot了。
3.建立CHROOT所需的环境:
(1)必须具备的目录:(假设$CHROOT为希望建立的路径)
$CHROOT/etc $CHROOT/lib $CHROOT/bin
$CHROOT/sbin $CHROOT/usr/lib $CHROOT/usr/bin
$CHROOT/usr/bin $CHROOT/usr/local $CHROOT/home
(2)仔细审查/etc中的档案,需具备执行程序时所需的文件
案,如passwd,groups,hosts,resolv.conf等等。
(3)拿掉不想给的执行档,如su,sudo等SetUid的程序,
以及compiler甚至telnet。
(4)测试一下,以root身份执行 chroot $CHROOT /bin/sh
即可进入CHROOT环境中。(man chroot for details)
4.在console或是以telnet进入试试。
5.Username/Password Resolve的考虑:
在CHROOT时你可能不希望被CHROOT的使用者(以后简
称CHROOTer)能拿到/etc/passwd或是/etc/shadow等檔
案,尤其是有root密码的。以下有三种情形:
(1)/etc/passwd跟 $CHROOT/etc/passwd相同:
这是最差的作法,因为一来被CHROOTer有机会得到root
的encrypted password,二来要保持/etc/passwd及
$CHROOT/etc/passwd的同步性是个大问题。因为
/usr/bin/login参考的是/etc/passwd,可是一旦
CHROOTer被chroot后执行passwd时,他所执行的
passwd所更改的将是$CHROOT/etc/passwd。
(2)/etc/passwd跟$CHROOT/etc/passwd不同:
你可以把$CHROOT/etc/passwd中的重要人物(如root)
的密码拿掉,然后以比较复杂的方法修改
/usr/bin/login:
if (has_chroot_group) {
re-load $CHROOT/etc/passwd
if (password is valid) {
chroot($CHROOT)
exec(shell)
} else logout()
}
此法的好处是你可以将/etc/passwd跟
$CHROOT/etc/passwd分开来。/etc/passwd只影响
CHROOTer在login时所使用的username,其它如
password甚至uid,gid,shell,home等等都是参
考$CHROOT/etc/passwd的。
缺点是你其它的daemon如ftpd,httpd都必须做相同
的修改才能正确取的CHROOTer的信息,而且你在把一
个user加入或移出chroot_group时都必须更改
/etc/passwd跟$CHROOT/etc/passwd。
(3)使用NIS/YP:
此法大概是最简单,且麻烦最少的了。因为一切的user
information都经过NIS Bind来取得,不但可以保护住
root的密码,也省去/etc/passwd跟
$CHROOT/etc/passwd同步管理上的问题。不只是
passwd,连其它如groups,hosts,services,
aliases等等都可以一并解决。
* 其它必须考虑的问题:
1.执行档的同步性:
再更新系统或是更新软件时,必须考虑到一并更换
$CHROOT目录下的档案,尤其如SunOS或是BSD等会用
nlist()来取得Kernel Information的,在更新kernel
时必须更新$CHROOT下的kernel。
2./dev的问题:
一般而言你必须用local loopback NFS将/dev read-
write mount到$CHROOT/dev以使得一般user跟CHROOTer
可以互相write以及解决devices同步性的问题。
3./proc的问题:
在Linux或是SYSV或是4.4BSD的系统上许多程序会去
参考/proc的数据,你必须也将/proc mount到
$CHROOT/proc。
4./var的问题:
一般而言/var也是用local loopback NFS read-write
mount到$CHROOT/var下,以解决spool同步性的问题,
否则你可能必须要修改lpd或是sendmail等daemon,
不然他们是不知道$CHROOT/var下也有spool的存在。
5.Daemon的问题:
你必须修改一些跟使用者相关的Daemon如ftpd,httpd
以使这些daemon能找到正确的user home。
* CHROOT无法解决的安全问题:
1.不小心或是忘记拿掉SetUid的程序:
CHROOTer还是有机会利用SetUid的程序来取得root的
权限,不过因为你已经将他CHROOT了,所以所能影响到
的只有$CHROOT/目录以下的档案,就算他来个
"/bin/rm -rf /" 也不怕了。
不过其它root能做的事还是防不了,如利用tcpdump来
窃听该localnet中的通讯并取得在该localnet上其它
机器的账号密码,reboot机器,更改NIS的数据,更改
其它没有被CHROOT的账号的密码藉以取得一般账号(所
以root不可加入NIS中)等等。
(此时就必须藉由securetty或是login.access或是将
wheel group拿出NIS来防止其login as root)
2.已加载内存中的Daemon:
对于那些一开机就执行的程序如sendmail,httpd,
gopherd,inetd等等,如果这些daemon有hole(如
sendmail),那hacker只要破解这些daemon还是可以取
得root权限。
* 结论:
CHROOT可以增进系统的安全性,限制使用者能做的事,
但是CHROOT Is Not Everything,因为还是有其它的
漏洞等着hacker来找出来。
所谓"监牢"就是指通过chroot机制来更改某个进程所能看到的根目录,即将某进程限制在指定目录中,保证该进程只能对该目录及其子目录的文件有所动作,从而保证整个服务器的安全。
创建chroot"监牢"
以前,Unix/Linux上的daemon都是以root权限启动的。当时,这似乎是一件理所当然的事情,因为像Apache这样的服务器软件需要绑定到"众所周知"的端口上(小于1024)来监听HTTP请求,而root是惟一有这种权限的用户。
但是,随着攻击者活动的日益频繁,尤其是缓冲区溢出漏洞数量的激增,使服务器安全受到了更大的威胁。一旦某个网络服务存在漏洞,攻击者就能够访问并控制整个系统。因此,为了减缓这种攻击所带来的负面影响,现在服务器软件通常设计为以root权限启动,然后服务器进程自行放弃root,再以某个低权限的系统账号来运行进程。这种方式的好处在于一旦该服务被攻击者利用漏洞入侵,由于进程权限很低,攻击者得到的访问权限又是基于这个较低权限的,对系统造成的危害比以前减轻了许多。
有些攻击者会试图找到系统其它的漏洞来提升权限,直至达到root。由于本地安全性远低于远程安全保护,因此攻击者很有可能在系统中找到可以提升权限的东西。即使没有找到本地漏洞,攻击者也可能会造成其它损害,如删除文件、涂改主页等。
为了进一步提高系统安全性,Linux内核引入了chroot机制。chroot是内核中的一个系统调用,软件可以通过调用库函数chroot,来更改某个进程所能见到的根目录。比如,Apache软件安装在/usr/local/httpd/目录下,以root用户(或具有相同权限的其它账号)启动Apache,这个root权限的父进程会派生数个以nobody权限运行的子进程,具体情况取决于个人设置。父进程监听请求自80端口的tcp数据流,然后根据内部算法将这个请求分配给某个子进程来处理。这时Apache子进程所处的目录继承自父进程,即/usr/local/httpd/。
但是,一旦目录权限设定失误,被攻击的Apache子进程可以访问/usr/local、/usr、/tmp,甚至整个文件系统,因为Apache 进程所处的根目录仍是整个文件系统的根。如果能够利用chroot将Apache限制在/usr/local/httpd/,那么,Apache所能存取的文件都是/usr/local/httpd/下的文件或其子目录下的文件。创建chroot"监牢"的作用就是将进程权限限制在文件系统目录树中的某一子树中。
为什么需要jail
将软件chroot化的一个问题是该软件运行时需要的所有程序、配置文件和库文件都必须事先安装到chroot目录中,通常称这个目录为 chroot jail(chroot"监牢")。如果要在"监牢"中运行/sbin/httpd,而事实上根本看不到文件系统中那个真正的/sbin目录。因此需要事先创建/sbin目录,并将httpd复制到其中。同时httpd需要几个库文件,执行如下命令可以看到这些库文件(在真实的文件系统下运行)。
#ldd /sbin/httpd
libaprutil-0.so.0 => /usr/local/httpd/lib/libaprutil-0.so.0 (0x40017000)
libgdbm.so.2 => /usr/lib/libgdbm.so.2 (0x4003c000)
libdb-4.0.so => /lib/libdb-4.0.so (0x40043000)
libpthread.so.0 => /lib/tls/libpthread.so.0 (0x400eb000)
libexpat.so.0 => /usr/lib/libexpat.so.0 (0x400f8000)
libapr-0.so.0 => /usr/local/httpd/lib/libapr-0.so.0 (0x40118000)
librt.so.1 => /lib/librt.so.1 (0x40139000)
lIBM.so.6 => /lib/tls/lIBM.so.6 (0x4014b000)
libcrypt.so.1 => /lib/libcrypt.so.1 (0x4016d000)
libnsl.so.1 => /lib/libnsl.so.1 (0x4019a000)
libdl.so.2 => /lib/libdl.so.2 (0x401af000)
libc.so.6 => /lib/tls/libc.so.6 (0x42000000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
这意味着还需要在"监牢"中创建lib目录,并将库文件复制到其中。这一工作可以交由计算机完成,用jail等软件包来帮助简化chroot"监牢"建立的过程。
编译和安装jail
从可以下载到jail的最新版本,它是由位于的jail chroot项目小组开发的。该软件包包含了帮助自动创建chroot"监牢"的C程序、Perl程序和Bash脚本。
首先将jail.tar.gz置于任意目录,然后执行命令:
#tar xzvf jail.tar.gz && cd jail/src
按照个人实际情况修改makefile文件,尤其是安装路径(默认安装路径是/usr/local)、体系结构(jail支持Linux、FreeBSD、IRIX和Solaris),以及编译选项等。最后执行命令:
#make && make install
为jail创建chroot"监牢"
现在创建一个目录作为chroot"监牢",以/var/chroot/为例。执行下面的命令为chroot"监牢"创建环境:
#/usr/local/bin/mkjailenv /var/chroot
这样"监牢"就建好了。jail软件包提供了几个Perl脚本作为其核心命令,包括mkjailenv、addjailuser和 addjailsw。如addjailsw会从真实文件系统中拷贝二进制可执行文件及其相关的其它文件(包括库文件、辅助性文件和设备文件)到该"监牢" 中。
为jail"监牢"添加软件
接下来需要为这个"监牢"增加一些软件,以便让它运行起来。执行以下命令安装一些基本的软件,包括ls、cat、cp等程序和ld-linux.so.2等库文件。
#/usr/local/bin/addjailsw /var/chroot
事实上仅有这些基本软件是不够的,还需要把一些真正有用的东西限制起来。下面的例子展示了为"监牢"添加arp程序的过程:
#/usr/local/bin/addjailsw /var/chroot -P arp
addjailsw
A component of Jail (version 1.9 for linux)
Juan M. Casillas <>
Guessing arp args(0)
Warning: file .//lib/tls/libc.so.6 exists. Overwritting it
Warning: file .//lib/ld-linux.so.2 exists. Overwritting it
Warning: file .//etc/ld.so.cache exists. Overwritting it
Warning: file .//usr/lib/locale/locale-archive exists. Overwritting it
Warning: file .//usr/share/locale/locale.alias exists. Overwritting it
Warning: can't create /proc/net/arp from the /proc filesystem
Done.
再以Apache服务器软件为例:
#addjailsw /var/chroot/ -P /usr/local/httpd/bin/httpd
addjailsw
A component of Jail (version 1.9 for linux)
Juan M. Casillas <>
Guessing /usr/local/httpd/bin/httpd args(0)
Warning: file /var/chroot//lib/libssl.so.4 exists. Overwritting it
Warning: file /var/chroot//lib/libcrypto.so.4 exists. Overwritting it
Warning: file /var/chroot//lib/libresolv.so.2 exists. Overwritting it
……
Done.
不用在意那些警告信息,因为jail会调用ldd检查httpd用到的库文件。而几乎所有基于共享库的二进制可执行文件都需要上述的几个库文件。
接下来将Apache的相关文件拷贝到"监牢"中:
#cp -a /usr/local/httpd/ /var/chroot/usr/local/
可根据个人情况依次将Apache需要的文件复制到"监牢"中。
"监禁"囚犯
有时候需要为chroot"监牢"创建新的用户,比如Apache要求创建nobody用户作为子进程用户。鉴于可能有其它进程使用nobody,还可以使用另一用户——httpd。首先需要在真实系统中创建httpd用户:
#useradd -d /var/chroot -s /usr/local/bin/jail httpd
然后执行以下命令在chroot"监牢"中创建httpd用户:
#/usr/local/bin/addjailuser /var/chroot /usr/local/httpd /usr/sbin/httpd httpd
接下来修改/var/chroot/usr/local/httpd/conf/httpd.conf,将User nobody替换为User httpd。由于chroot后Apache将以httpd身份启动进程,只有root有权将Apache绑定在低端口上(通常为80),因此还需要修改端口值,该值必须大于1024(假设为8080)。这个修改要应用到Apache的所有配置文件中,包括虚拟主机的配置。至于Apache的其它设置,与在真实文件系统时一样配置即可。
接下来需要复制一些其它的文件。启动Apache最常见的方式就是调用apachectl,这是个Bash脚本。查看这个文件,会发现如下行:
HTTPD='/usr/local/httpd/bin/httpd'
LYNX="lynx -dump"
ULIMIT_MAX_FILES="ulimit -S -n `ulimit -H -n`"
ARGV="-h"
$HTTPD -k $ARGV
$HTTPD -k start -DSSL
$HTTPD -t
$LYNX $STATUSURL | awk ' /process$/ { print; exit } { print } '
其中ulimit、lynx和awk是辅助性的程序。另外需要注意的是,程序使用不同的参数时,可能会使用不同的库文件,因此为了让Apache完整运行,使用下面的命令来跟踪所有可能的文件:
#/usr/local/bin/addjailsw /var/chroot -P httpd "-k start -DSSL"
用上述的参数替换引号中的参数,完成全部的工作。
最后,让成功jail的Apache运行起来:
#su - httpd &
打开浏览器进行测试,访问Web服务器时记住加上8080端口号。
jail高级应用
在前面的介绍中,使用了jail软件包中的三个Perl脚本。这里详细介绍这三个脚本的使用,以便高级用户使用。
mkjailenv
用法:mkjailenv chrootdir
作用:创建chroot"监牢"目录,并且从真实文件系统中拷贝基本的软件环境。
参数:
chrootdir指定chroot"监牢"的路径。
addjailsw
用法:addjailsw chrootdir [-D] [-P program args]
作用:从真实文件系统中拷贝指定的文件及其相关文件。
参数:
chrootdir指定chroot"监牢"的路径。
-D显示详细信息。
-P program args指定要添加到"监牢"中的软件。program可以是个文件名,也可以是文件的完整路径;args是参数。比如可以这样执行addjailsw:
#addjailsw /var/chroot -P vi "-c q"
addjailuser
用法:addjailuser chrootdir userdir usershell username
作用:创建新的chroot"监牢"用户。
参数:
chrootdir指定chroot"监牢"的路径。
userdir指定新添加用户的主目录(相对于chroot"监牢"目录)。
usershell指定新用户使用的Shell的完整路径(比如/bin/bash)。
username为新添加的用户名。
比如:
#addjailuser /var/chroot /home/ftp /bin/csh ftp
这个脚本会自动修改"监牢"中的/etc/passwd、/etc/group和/etc/shadow文件。
从上文看,如果仅使Apache一个软件运行在"监牢"中,mkjailenv似乎过于"热心"了,因此可以不运行mkjailenv /var/chroot命令,而只运行addjailsw /var/chroot -P httpd或在调试完chroot"监牢"后删除多余的文件,并修改/etc/passwd中多余的用户信息。由此想到,现在大多数流行的Web站点都采用Apache+PHP+MySQL+SSL的搭配(可能还会有FTP、Mail、Perl等组件),因此完全可以建立一个综合的Web"监牢"。系统管理员可以为这个"监牢"设置软件环境,当然这个环境只包括维护Apache+PHP+MySQL+SSL这些组件的必备工具,如使用Bash、SSH、编译软件或上传等。这可能是一个浩大的工程,但是却非常有意义。参考上面的方法,大家可以尝试jail出完美的服务器来。