本文中,作者将为大家讲述如何使用chroot保障开源系统服务安全。
1、主要功能
在早期的UNIX系统中,根目录是文件系统中的一个固定点。在当前UNIX变体中,包括Linux,你可以在每个进程的基础上定义根目录。chroot实用程序程序允许你用根目录(而非/)运行一个进程。
根目录位于目录层次结构的顶部,并且没有父目录。因此,一个进程无法访问根目录以上的文件,因为不存在。例如,如果运行一个程序(进程),指定其根目录为/home/sam/jail,该程序没有/home/sam中的任何文件的概念:jail是该程序的根目录,并标记为/(不是jail)。
通过创建一个人工的根目录,通常被称为(chroot)jail,可以防止一个程序访问、执行或修改(可能恶意)始自其根目录层次结构之外的文件。你必须正确设置一个chroot jail以提高安全性:如果你没有正确设置chroot jail,恶意用户会比没有chroot jail更容易获得访问系统的权限。
2、使用chroot
1)创建chrot jail
创建一个chroot jail很简单:使用root权限,执行/usr/sbin/chroot directory命令。其中directory成为根目录,该进程试图运行默认shell。使用root权限,下面的命令在(现有的)/home/sam/jail目录中设置一个chroot jail:
# /usr/sbin/chroot /home/sam/jail
/usr/sbin/chroot: failed to run command '/bin/bash': No such file or directory
这个例子设置一个chroot jail,但是当系统试图运行bash shell时,操作失败。一旦设置了jail,名为jail的目录将取代根目录的名称/。因此,chroot环境无法找到由/bin/bash路径名标识的文件。在这种情况下chroot jail正常工作,但没有用处。
让chroot jail按你想要的方式工作是较为复杂的。要让前面的例子在chroot jail中运行bash,在jail (/home/sam/jail/bin)中创建一个bin目录并将/bin/bash复制这个目录。由于bash二进制文件是到共享库的动态链接,你还需要将这些库文件(在lib中)复制到jail中。
2)一个具体的例子
下面的示例创建必要的目录、复制bash、使用ldd来显示bash依赖的共享库以及复制必要的库文件到lib中。 linux-gate.so.1文件是一个动态共享对象(DSO),由内核提供以加速系统调用,不必复制它。
$ pwd
/home/sam/jail
$ mkdir bin lib
$ cp /bin/bash bin
$ ldd bin/bash
linux-gate.so.1 => (0×00988000)
libtinfo.so.5 => /lib/libtinfo.so.5 (0×0076b000)
libdl.so.2 => /lib/libdl.so.2 (0×00afb000)
libc.so.6 => /lib/libc.so.6 (0×00110000)
/lib/ld-linux.so.2 (0×00923000)
$ cp /lib/{libtinfo.so.5,libdl.so.2,libc.so.6,ld-linux.so.2} lib
现在再次启动chroot jail。虽然一个普通用户可以完成所有设置,但必须使用root权限来运行chroot:
$ su
Password:
#/usr/sbin/chroot .
bash-4.1# pwd
/
bash-4.1# ls
bash: ls: command not found
bash-4.1#
这一次chroot查找并启动bash,显示其默认的提示符(bash-4.1#)。pwd命令工作,因为它是一个shell内置命令。然而,bash无法找到ls命令,因为它不在chroot jail中。如果想要jail中的用户能够使用ls,可以把/bin/ls及其库文件复制到jail中。exit命令允许你从jail退出。
如果为chroot提供第二个参数,它把该参数作为jail内运行的程序的名称。下面的命令与前一个等价:
# /usr/sbin/chroot /home/sam/jail /bin/bash
要建立一个有用的chroot jail,首先要确定chroot jail的用户需要哪些实用程序。然后将相应的二进制文件及其库文件复制到jail中。或者,可以建立二进制文件的静态副本并把它们放入jail中,无需安装单独的库。(静态链接二进制文件大大超过其对应的动态二进制文件。bash基本系统及其核心工具的规模超过50兆字节。)你可以在bash和coreutils SRPMS(源RPM)软件包中找到最常用工具的源代码。
chroot实用程序将失败,除非以root权限运行。以root权限运行chroot的结果是一个root shell(具有root权限的shell)运行在chroot jail内。由于具有root权限的用户可以突破chroot jail,当务之急是在chroot jail中要以降低的特权运行一个程序。
有几种方法可以降低用户的特权。例如,可以把su或sudo放在jail中,然后启动shell或jail内的守护程序,使用这些程序之一,来降低在jail中工作的用户的特权。以下命令以jail中降低的特权启动一个shell:
# /usr/sbin/chroot jailpath /bin/su user -c /bin/bash
其中jailpath是jail目录的路径名,以及user是shell以特权运行的用户名。这种情况下的问题是sudo和su调用PAM。要运行这些实用程序之一,需要把所有的PAM,包括它的库和配置文件,与sudo (或 su)和/etc/passwd文件一起放在jail中。或者,可以重新编译su或sudo。然而,其源代码调用PAM,所以需要修改其源代码以便它不调用PAM。这些技术既费时又引入了复杂性,从而导致不安全的jail。
下面的C程序以降低的特权运行chroot jail中的一个程序。因为该程序在调用chroot()之前获取你在命令行上指定的用户的UID和GID,不需要把/etc/passwd放入jail。该程序降低了指定用户的指定程序的特权。该程序为前面的问题提供了一个简单的解决方案,所以你可以试验chroot jail并更好地理解其工作原理。
$ cat uchroot.c
/* See svn.gna.org/viewcvs/etoile/trunk/Etoile/LiveCD/uchroot.c for terms of use. */
#include
#include
#include
int main(int argc, char * argv[])
{
if(argc < 4)
{
printf("Usage: %s {username} {directory} {program} [arguments]\n",
argv[0]);
return 1;
}
/* Parse arguments */
struct passwd * pass = getpwnam(argv[1]);
if(pass == NULL)
{
printf("Unknown user %s\n", argv[1]);
return 2;
}
/* Set the required UID */
chdir(argv[2]);
if(chroot(argv[2])
||
setgid(pass->pw_gid)
||
setuid(pass->pw_uid))
{
printf("%s must be run as root. Current uid=%d, euid=%d\n",
argv[0],
(int)getuid(),
(int)geteuid()
);
return 3;
}
return execv(argv[3], argv + 3);
}
以下命令的第一行使用cc(gcc软件包)编译uchroot.c,创建一个uchroot可执行文件。后续命令将uchroot移入/usr/local/bin目录,并给予相应的所有权。
$ cc -o uchroot uchroot.c
$ su
password:
# mv uchroot /usr/local/bin
# chown root:root /usr/local/bin/uchroot
# exit
$ ls -l /usr/local/bin/uchroot
-rwxrwxr-x. 1 root root 5704 12-31 15:00 /usr/local/bin/uchroot
使用本节前面的设置,执行下面的命令以chroot jail内用户sam的特权运行一个shell:
# /usr/local/bin/uchroot sam /home/sam/jail /bin/bash
如果你计划部署多个chroot jail,最好保存bin和lib目录的一个干净副本。
3、运行chroot Jail中的一个服务
运行jail内的shell,用处不大。在现实中,你更可能要运行jail内的一个特定服务。要运行jail内的服务,确保该服务所需的所有文件在jail内。使用uchroot在chroot jail中启动一个服务的命令格式为:
# /usr/local/bin/uchroot user jailpath daemonname
其中jailpath是jail目录的路径名,user是运行守护进程的用户名,daemonname是提供服务的守护进程的路径名(jail内)。
已经设置了某些服务器来利用chroot jail。例如,可以设置DNS以便named运行在jail中,以及vsftpd FTP服务器可以为客户端自动启动chroot jail。
4、安全性考虑
有些服务需要由具有root权限的用户或进程来运行,但一旦启动就释放其root权限(例如Apache、Procmail和vsftpd)。如果运行这样的服务,不必使用uchroot或者把su或sudo放入jail内。
以root权限运行的进程有可能从chroot jail退出。出于这个原因,在启动一个运行在jail内的程序之前,应该降低特权。此外,慎重对待jail内允许的setuid二进制文件—其中的安全漏洞可能会危及jail的安全。此外,确保该用户不能访问他上传到jail的可执行文件。