LINUX内核级安全审计系统的设计与实现

时间:2022-10-02 08:11:10

LINUX内核级安全审计系统的设计与实现

摘要:审计系统作为安全操作系统的重要组成部分,在系统监测中起着重要作用,它确保安全策略的正确实现和入侵检测系统的建立。原始的基于应用的Linux审计体系存在固有的缺点,应该对此进行改善。该篇介绍了在Linux内核中安全审计系统的设计与实现。在Linux内核中实现了基于可加载内核模块的安全审计模型并运用了一种新的基于复制中断描述表的系统调用拦截的方法。此外,该系统能在内核中全面采集信息,并且采取了有效的方法保护审计系统自身的安全。

关键词:安全审计;可加载内核模块;中断描述表

中图分类号:TP311文献标识码:A文章编号:1009-3044(2008)14-20835-02

1 引言

通过对现实社会管理方式的模仿,审计被引入到计算机系统中并主要应用于监视系统行为。审计系统作为安全操作系统的重要组成,将用于监视,记录和控制计算机系统的安全行为。它的主要功能是检测和阻止非法用户的系统入侵和提示合法用户的错误操作。在公用的Linux操作系统中,日志机制实现了相似的功能。但是日志机制在审计粒度,审计安全和审计灵活性方面存在着明显的缺陷。

现有的Linux的审计机制是基于应用层面的。典型的审计系统如“syslogd”(一种用于邮件收发的后台程序)。它主要应用于从各种受限制的服务(klogd,httpd,inetd,etc)中获取重要的信息,并且根据配置文件实现通讯处理。不同的类型有明显不同的输出模式并且这些输出将被保存到不同的日志文件中。原始的Linux审计系统中有以下安全问题:首先,一旦某用于收集审计数据的外部服务程序被恶意用户破坏,这些审计数据将不会被记录下来,因为服务程序运行于用户状态。其次,即使审计信息在用户状态被收集,这些信息也是不充分,不详细的。例如,只有系统调用名被记录,而不会提供与其相关的其他信息。在者,这里没有足够的方法来保护已存在的日志文件。换句话说,这些日志文件能够被其他用户访问,篡改和删除。而且,没有有效的方法去检查,分析这些审计信息。因此,我们应该改善原始的Linux审计机制,加强审计日志安全性的管理。

在这篇文章中,提供了详细的安全审计系统在Linux内核中的设计和实现。该系统实现了一种新的基于中断描述表的系统拦截方法的调用。

2 安全审计系统的设计

内核作为操作系统中重要的组成部分,主要用于进程控制,内存寻址和管理,系统调用等方面。一个运行的Linux操作系统分为用户状态和内核状态。就用户程序而言,它们可以利用各种系统资源,如:文件,目录,外设等,只有当系统调用时进入内核状态,处理完成后,用户程序又返回到用户状态。因此我们可以基于这种机制在内核中设置审计指针记录关于系统运行状态的详细信息。这种审计机制的优越性在于:首先,所有的审计信息产生于内核。任何系统当前状态的行为都能够被真实的记录下来,因此审计信息可以避免被恶意用户在应用层破坏;其次,审计信息在内核中得到保存和处理,这种方式可以避免信息在黑客入侵后被删除或破坏。

2.1 可加载内核模块(LKM)

可加载内核模块是一种扩充操作系统功能的机制。新的内核代码可以在不重新编译内核的状况下通过动态加载直接执行。因此,可加载内核模块被用于特定设备的驱动程序。所有的可加载内核模块都包含两种基本函数:“int init_module(void)”和“void cleanup_module(void)”,这用于模块的初始化和模块的卸载。被加载的模块只是内核中运行的一段代码,它可以访问内核中许多机密部分。黑客可以利用KLM成功入侵内核,同样,我们也可以利用这种技术保护内核。

2.2 系统调用拦截

系统调用作为应用程序与操作系统内核的接口,它返回调用操作系统特定功能的用户程序的执行结果。当用户程序执行相应的系统调用,将传送给系统调用函数所需的所有信息。因此,我们可以在内核拦截这些系统调用,从这些特定的系统调用中获取审计信息并通过设备文件将信息保存到用户区域。在Linux中,指令“int ox80”被用于执行系统调用。做为用户和内核的接口,外壳用于解释和执行用户命令和程序。分析用户命令是外壳的基本操作。然后相关的子进程通过”execve()”函数得到执行。如果关于“execve()”的系统调用可以被拦截,我们就可以得到用户所要执行的相关命令的审计信息。

主要的系统拦截过程如下:找到系统调用的入口(“sys_call_table[]”)在sys_call_table[]”中保存函数的原始入口指针;把用户函数指针放入“sys_call_table[]”。在用户程序中首先保存相关的系统调用审计信息,然后执行“execve()”。

为了避免系统调用被恶意的修改和取代,系统调用不能直接从“sys_call_table[]”输出(内核版本2.4.18)。研究发现Linux内核对特定部分产生中断,我们就可以通过复制中断描述表(IDT)实现新的系统调用的拦截。

IDT是一个关于系统中断或异常向量的表。每个向量有相应的中断入口或异常处理程序。在Linux中有256个中断向量;“ox80”是用来执行系统调用的。IDT由任务门,中断门,陷阱门组成。系统调用利用中断门。每个IDT的入口由8字节的描述符表示。中断门由64位的描述符来表示。中断程序的入口地址由“handler offset low”和“handler offset high”两部分组成。当中断发生,中断程序就被调用,执行。IDT寄存器可以使IDT位于内存的任意空间,并且指定物理的入口地址和IDT的最大长度。指令“sidt“可以查找IDT在内存中的入口地址并且系统调用的入口地址可以在IDT中找到。当检测到“system_call”的源码(在“/arch/i386/kernet/entry.s”),我们可以发现申明“call SYMBOL_NAME(sys_call_table)(,%eax,4)”依照系统调用应用于转变,同时“SYMBOL_NAME(sys_call_table)”的执行结果是“sys_call_table[]”的入口地址。因此,如果找到了申明“call something(,%eax,4)”,我们就可以找到“sys_call_table[]”的入口地址。这条申明的机器指令代码是“oxff ox14 ox85”。

在找到“sys_call_table[]”的入口地址后,我们用新定制的函数“hacked_execve()”代替原有的函数“execve()”。新的函数主要用于从进程描述符中获得审计信息,然后执行最初的外壳程序。进程描述符是“task_struct”结构体类型,由所有的进程信息组成。我们可以从“task_struct”结构体中获得审计信息。由于进程描述符包含大量的信息,因此审计信息通常只包含“task_struct”结构体中的部分信息。

2.3 设备驱动程序

Linux内存被划分为内核空间和用户空间。一般用户进程不能够访问内核空间,同样内核空间也不能访问用户空间进程。这里有两个方法用于建立可加载内核模块程序(LKM)与用户空间进程间的通讯:“proc”文件系统或设备文件。由于LKM与设备驱动程序的紧密联系,所以利用设备驱动程序更为方便。

上一篇:数据库的并发控制 下一篇:VLAN技术在实际应用的方案设计探讨