linux内核 攻击,针对Linux内核提权攻击防御方法的研究

摘要:本文提出了一种基于Intel SMEP的轻量级的内核控制流完整性防御方法,以防御exploit-db中常见的内核提权攻击。该方案通过分离内核钩子函数的解引用和验证操作,在解引用处记录钩子函数,在敏感函数内验证钩子函数是否合法,防止恶意进程利用内核代码漏洞,修改全局函数钩子,导致内核中的敏感代码被恶意执行。

关键词:Linux内核 SMEP 提权攻击

中图分类号:TP393 文献标识码:A 文章编号:1007-9416(2013)04-0210-02

1 引言

在现有的针对Linux内核的攻击中,提权攻击无疑是造成危害最严重的一种。提权攻击是指攻击者利用代码漏洞,将进程权限从非root状态提升到root状态的过程。这类漏洞可能存在于各种服务器软件中,也可能存在于内核代码本身。本文旨在研究一种保护方式,以动态防御针对内核本身漏洞的提权攻击。本文的工作主要在两个方面:第一,总结了exploit-db[1]中针对Linux内核的攻击手段,提出一种常见的攻击模式,即利用内核代码漏洞攻击内核堆上的静态函数钩子,进而进行提权操作;第二,提出了一种实用的针对这种攻击模式的防御手段,即分离钩子函数的解引用和验证操作,以较低的性能开销保证内核中的敏感函数不被恶意篡改的钩子函数调用。

2 现有的攻击和防御手段

2.1 现有的攻击手段

现有的针对Linux内核的权限提升攻击,通常利用内核代码漏洞,篡改内核函数钩子,使其指向内核中的敏感函数。在exploit-db中,我们找到了以下这类攻击的几个例子:(1)CVE-2011-1495,内核_ctl_do_mpt_command函数中,调用copy_from_user时未检查数据的长度,导致内核堆缓冲区溢出和钩子覆盖问题。(2)CVE-2011-1169,内核asihpi_hpi_ioctl函数中,对数组赋值时没有检查偏移值是否合法,可能导致钩子被覆盖。(3)CVE-2011-1017,内核中ldm_frag_add函数调用memcpy时未检查数据长度,可能导致堆缓冲区溢出和钩子被覆盖。(4)CVE-2011-1016,Radeon GPU驱动程序中缺少对寄存器值的检查,可能导致模块相关的内存被改写。(5)CVE-2010-4656,iowarrior_write函数没有正确分配内存,可能导致缓冲区溢出,从而覆盖钩子函数的值。(6)CVE-2010-3904,RDS协议在使用_copy_*_user_inatomic宏时,对参数指针检查不足,可能导致内核数据段上的钩子函数被修改。

由此可以看到,Linux内核代码的漏洞会引发内核控制流被改变,恶意用户可以将控制流引导至用户态代码,或直接调用内核的敏感函数,获得更高权限,进行进一步攻击。本文主要讨论如何保护由内核代码漏洞引发的堆内存上指针篡改导致的权限提升攻击。

2.2 现有防御手段

2.2.1 基于硬件的防御手段

现有的基于硬件的防御手段主要有两类,第一类不需要引入虚拟机监控器,第二类需要在硬件虚拟化的条件下引入虚拟机监控器。第一类机制由Intel CPU提供,即SMEP[2]和SMAP[3]机制。SMEP机制用于防止运行在0环的进程执行3环内存中的代码,而SMAP机制用于防止运行在0环的进程访问3环内存中的数据。在SMEP机制的保护下,即使攻击者修改内核函数钩子,也只能将其指向内核代码本身。而在保证内核代码本身安全的前提下,攻击者很难通过这样的方式进行复杂的功能操作如访问磁盘文件等。第二类机制典型的工作如SecVisor[4],它通过在操作系统中引入虚拟机监控器来保证内核的控制流完整,它可以确保内核代码段不被修改,并且只有经过用户认证的代码才能被0环运行。但是,同样的,恶意用户可以通过修改内核数据段上的函数钩子,使其指向内核本身的代码段,或是通过ROP[5]攻击劫持内核控制流。由于引入了虚拟机监控器(VMM),相比于直接在物理硬件上运行的Linux系统,SecVisor的性能开销为前者的20倍以上。针对内核ROP攻击,Baozeng Ding[6]等人提出了一种防御手段。Hooksafe[7]通过将分散在内核中的钩子放入不可写的内存页中,使用监控器监控所有写操作,也达到保护内核钩子的效果,其性能在使用了Xen(通常会带来20%-40%的性能下降)的基础上另外带来了6%的性能下降。

2.2.2 基于软件的防御手段

基于软件的防御手段,通常会修改内核源代码或二进制代码,在其中加入相关的保护机制。PaX是一个Linux内核上成熟的产品,它以补丁的形式修改内核,给内存页表添加保护位,将代码段内存标记为不可写,数据段标记为不可执行,防止内核执行用户态恶意注入的代码。Vasileios P.Kemerlis等人设计的kGuard系统思想与本文类似,通过二进制插桩内核控制流转移指令,防止其调用用户空间函数。此时,攻击者仍然可以修改内核指针,使其指向内核空间本身的敏感函数,完成恶意操作。kGuard的性能开销为10%。Linux内核引入的ASLR机制可以很好的防止攻击者定位用户态目标代码的位置,防止恶意用户篡改钩子,使其指向已知的用户代码。但是,相比于用户态代码,内核代码段无法进行地址随机化,因此无法防止攻击者将钩子指向内核代码本身。对于大部分服务器应用来说,限制其使用系统调用无疑会限制其功能的正常运转。

2.2.3 本文攻击模型

在本文的攻击模型中,攻击者利用内核代码漏洞,将内核钩子指向内核代码本身。此时,攻击者无法控制内核栈,因此无法向被调用的内核代码传递参数。但是,通过实验我们发现,在这样的情况下,攻击者可以调用内核中不带参数的函数,完成一定的功能。在系统调用中,攻击者会受到如DAC、MAC、权能等各类机制的检查。所以,攻击者修改内核钩子,首先需要进行提权操作,通过恶意手段影响安全机制的运行,以此作为下一步攻击的基础。

3 改进的内核钩子保护框架

在SMEP机制的基础上,为了进一步防止攻击者修改内核钩子,将其指向内核代码本身,进行提权攻击,本文提出了一种基于软件的轻量级防御方案。在传统的防御方案中,若要验证钩子函数是否指向指定的目标地址,需要在其解引用时进行验证,而验证所需的查表操作会给系统带来数十倍的性能开销,因而这种方法并不实用。针对exploit-db中攻击者常用的攻击模式,通过分离钩子函数解引用、钩子函数验证这两个关键步骤,提出了一个可实际运行的内核钩子保护系统的设计方案。

3.1 系统概要

钩子函数通常以形式s->f_op(args)被调用。其中,s为包含钩子函数的结构体的对象,f_op为结构体中钩子函数的名称。如果钩子函数被攻击者恶意修改,那么符号f_op会指向一个不同的地址,这个地址可能是一个内核函数,或是用户空间的一段代码。如图1所示,攻击者将f_op的值从b改为恶意代码的地址c。在2.2.3中我们已经介绍过,攻击者劫持内核控制流后,首先需要获得内核权限,否则难以进行进一步的攻击。

因此,f_op被修改后,控制流会被劫持到内核中涉及权限的敏感代码处,而此时f_op函数的调用尚未返回。因此,系统在钩子函数赋值时记录值对(a,b),在f_op函数调用前,记录钩子函数的地址a,在涉及权限的敏感代码真正执行操作之前,检查所有已经记录的钩子函数的地址a保存的值b’是否与之前记录的b地址一致,若不一致,则认为钩子函数被恶意用户篡改,并且恶意用户试图执行权限相关的敏感操作。检查操作的性能开销可以忽略不计,系统主要的开销是相对于正常钩子函数调用操作而言新增加的保存和删除操作。由于保存和删除操作伴随钩子函数的调用和返回,因此我们在系统中开辟一小段内存模拟虚拟栈,使用压栈和退栈的方式保存和删除,可以使这两个操作都在约10条指令的操作时间内完成。

3.2 内核钩子函数的插桩

我们可以对内核钩子函数进行插桩,修改钩子函数的调用上下文,最基本的插桩前后代码片段如图2所示。在实际调用环境中,钩子函数还可能被以各种形式调用。Coccinelle[14]工具可以很好地针对这些特定的形式进行特定的插桩操作。

3.3 敏感函数选取

攻击者篡改内核钩子后,仍然需要通过系统调用进入内核,此时,内核会调用被篡改后的钩子,也就是攻击者需要执行的敏感函数。但是,由于攻击者无法控制内核栈,因此只能调用不带参数的函数进行提权操作。系统对符合以下条件的函数进行检查,在这些函数的入口位置增加检查代码,验证虚拟栈上保存的钩子函数是否合法:(1)位于内核security目录或kernel目录下权限相关的文件中,且直接修改内核安全数据域(cred结构体)或安全系统运行状态。(2)调用时不需要参数。

实际环境中,我们找到以下函数,作为样例配置输入,如表1 所示。

3.4 钩子函数的记录

我们在系统中增加学习模块,用以记录内核钩子函数的地址。在学习模块工作状态下,原有的shadow_push函数的作用不再是记录钩子函数的保存地址,而是将该地址转交给学习模块。学习模块获得这个地址后,检查这个地址是否被记录过,如果没有,则记录这个地址及其地址上对应的值。

4 系统分析

由于系统防止篡改后的钩子函数调用内核敏感函数,因此攻击者无法利用内核代码漏洞,通过函数钩子实施提权攻击。

由前面的描述我们可以看到,为了降低性能开销,我们可以将钩子函数的解引用操作和验证操作进行分离,在真正需要验证的调用点进行开销较大的验证操作,在解引用点处进行开销很小的压栈和退栈操作。在内核实际运行环境中,这样的分离只会引入很小的性能开销,原因有三:(1)系统的敏感函数通常由内核本身进行调用,正常模块不会调用这些函数修改自己的权限,而内核本身只包含少量的函数钩子。因此,在验证点处只需要验证很少一部分钩子的地址即可。(2)系统的敏感函数通常只在进程初始化阶段使用,用来构造进程沙箱环境。在进程实际运行时,进程使用的权限相关的标志位很少变化。因此,对于正常运行的系统,开销较大的验证操作很少被调用。(3)解引用点处引入的压栈和退栈操作对应为若数条内存读写指令,开销可以忽略不计。

5 结语

本文总结了exploit-db中常见的内核权限提升攻击模式,即通过修改内核全局钩子调用敏感函数进行提权攻击,并针对这种模式提出了相应的防御方法。通过插桩内核钩子函数的调用上下文,配合内核中的检查模块,检查函数钩子是否被篡改。本系统以5%的性能开销达到实时防护的效果。为了实现更完善的保护,今后需要针对内核的动态钩子函数进行处理。由于动态钩子函数无法通过符号文件定位,因此缓冲区溢出覆盖成为攻击这种钩子的主要方式,我们需要结合静态程序分析技术,监测和防止内核缓冲区溢出,来保证动态钩子不被恶意篡改。

参考文献

[1]exploit-db..

[4]Spengler B.Grsecurity acl documentation v1.5[J]/gracldoc.pdf,2003,40.

[5]Team,PaX,PaX address space layout randomization (ASLR).2003.

[6]Barth A,Jackson C,Reis C,et al.The security architecture of the Chromium browser[J].2008.

[7]Coccinelle:A Program Matching and Transformation Tool for Systems Code,2009.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值