邢柳
北京航天长征科技信息技术研究所 北京 100076
Linux的系统调用的函数指针存放在系统调用符号表(sys_call_table)中。通过一些特殊的手段,我们可以更改其中系统地址的指针将系统调用引导到自己的程序代码中,从而实现特定功能。使用LKM替换系统调用,我们可以在不重新编译内核的情况下,为Linux系统增加或完成一些特殊形式的功能。
文件系统的属性对于提高文件系统的安全性和保障文件系统的完整性(尤其对于系统日志文件)有很大的作用。chattr正是设置文件系统属性的用户接口命令。注意,该命令的使用必须是root用户,其他用户即使是文件的所有者对该文件使用chattr命令也会显示“不允许的操作”的错误提示。系统管理员把系统的重要文件添加上隐藏属性,以防止系统重要文件被删除或篡改。比如使用了命令:
chattr + a message.txt
对message.txt文件设置了append属性后,系统只允许在这个文件末尾追加数据,不允许任何进程覆盖、截断或者删除这个文件。实验结果显示,message.txt只能被添加,而不准修改。
在Linux系统中,如果一个用户以root的权限登录,文件系统的权限控制将无法对root用户和以root权限运行的进程进行任何的限制。这样对于Linux操作系统,如果攻击者通过远程或者本地攻击获得root权限将可能对系统造成严重的破坏。而ext2文件系统可以作为最后道防线,最大限度地减小系统被破坏的程度,并保存攻击者的行踪。ext2属性是由 sys_open()和 sys_truncate()等系统调用检查和赋予的,不受用户识别号和其他因素的影响,在任何情况下,对具有不可修改(immutable)属性的文件的进行任何修改都会失败,不管是否是root用户进行的修改。
如果root用户去掉了文件的隐藏属性,就可以对该文件进行任意的删除、修改等操作。本文对系统进行的保护措施是:先对系统重要文件设置隐减属性,然后加载本文提出的安全保护模块。目的是使root用户也不能更改文件的隐藏属性,即不能篡改要保护的文件。从而保证系统重要文件不被破坏和删除。
众所周知,Linux内核中有大量安全特征,其中有很多特征有着广泛的应用,但是绝大多数的系统管理员(包括一些资深系统管理员)都忽略了 ext2文件系统的隐藏属性(attribute)。Linux的这种安全特征甚至远没有Lids和Tripwire等外部安全工具受关注,但是使用这个特征可以很好地保护系统的安全。从Linux的1.1系列内核开始,ext2文件系统就开始支持一些针对文件和目录的额外标记或者叫做属性(attribute)。ext2文件系统支持表1列出的属性设置。
在这些属性中,最为重要的是a(Append Only)属性和不可修改(immutable)属性,它们对于提高文件系统的安全性和保障文件系统的完整性(尤其对于系统日志文件)有很大的作用。另外,由于ext3文件系统是以ext2文件系统为基础的,因此所有ext2文件系统支持的属性,ext3文件系统也都支持。
替换系统调用就是我们自己构造一个系统调用,想办法使 sys_call_table相应的系统调用号指向我们自己构造的函数。在原来的2.4内核里,可以将sys_call_table直接导出,这样我们就很容易拿到sys_call_table的控制权来实现系统调用的替换,但是从2.6的版本以后,考虑到安全问题不允许将sys_call_table再导出,这样就加大了取得syscall_table控制权的难度。下面讨论获取sys_call_table地址的方法。
在内核代码中存在许多符号(symbol),特别是大量的全局符号,内核通过它的地址,如c02f94a0这样的符号来使用变量,但是直接使用地址来引用变量又给内核编程带来了很大困难,所以内核提供了一种折中的方案,即将每个符号和其对应的地址保存在一个文件中,这样既可在编程开发时使用符号,又可以方便的得到其地址。System.map就是保存这种对应关系的文件。它通常位于/boot/System.map,在其内部记录了内核各个符号的内存定位信息。通过文本文件搜索,我们可以获取sys_call_table的地址,并作为LKM模块加载时的传递参数。
vmlinuz是可引导的、压缩的内核,其中“vm”代表“Virtual Memory”,通常位于/boot/vmlinuz,一般是在编译内核时通过“make zImage”创建或make bzImage创建,然后通过拷贝产生,在开头部分内嵌有gzip解压缩代码。由内核文件中包含的一个微型的 gzip用于解压缩内核并引导它。vmlinux是未压缩的内核,vmlinuz是vmlinux的压缩文件。通过shell命令:grep sys_call_table/boot/System.map或nm vmlinux grep sys_call_table就可以获得sys_call_table的地址。
替换系统调用可以通过中断向量取得 sys_call_table地址。基本思路是这样的,因为系统调用都是通过 0x80中断来进行的,故可以通过查找 0x80中断的处理程序来获得sys_call_table的地址。其基本步骤是,首先获取中断描述符表的地址,再从中查找 0x80中断的服务例程,再搜索该例程的内存空间,以从其中获取sys_call_table的地址。
chattr命令最终执行进sys_ioctl()系统调用里,所以,我们替换调用原有的sys_ioctl()函数。在新的sys_ioctl()函数里面,根据传进的参数进行判断,如果用户输入的是要求改写文件属性的chattr命令,那么就可以通过dbgprint函数调用printk,输出信息到环形buffer,该信息由klogd取出,交给syslogd存到系统日志文件/.var/log/messages里面,管理员查看该日志,会发现有人想要执行该操作,根据该信息输出的时间,能判断出是否合法用户在执行这条命令。
本文的测试环境是Fedora core 5。在模块hijack.ko里面,通过替换sys_ioctl()系统调用,实现了监控 root用户修改文件隐藏属性功能。测试步骤如表2所示。
表2 监控特权命令chattr测试步骤
本文使用LKM替换系统调用,实现监控特权命令的执行。以监控chattr命令执行为例。本文的安全实现前提是,系统管理员把系统的重要文件添加上隐藏属性,以防止系统重要文件被删除或篡改。设置完各种隐藏属性后,安装hijack模块,防止不法用户获取到root口令,破坏系统重要文件。
[1]李善平,季江民,尹康凯.边干边学—Linux内核指导(第二版)[M].杭州:浙江大学出版社.2008.
[2]倪继利.Linux安全体系分析与编程[M].北京:电子工业出版社.2007.
[3]赵亮.探索Linux内核级安全增强系统[J].开放系统世界.2003.
[4]王艳丽.浅谈Linux用户管理[J].电子科技.2010.
[5]曹云鹏.关于 Linux操作系统用户管理的研究[J].科技情报开发与经济.2003.
[6]陈向阳,方汉.Linux实用大全[M].北京:科学出版社.1998.