栈随机化

2024-09-23

栈随机化(精选4篇)

栈随机化 篇1

0 引言

计算机科学技术高速发展,在给人们带来便利的同时信息安全的问题困扰着每一位计算机用户[1]。软件结构越来越复杂,而软件中各种漏洞及被恶意植入的后门层出不穷,相对应的防御机制一直处于被动地位,这种不对等的攻防形势致使互联网用户每天都处在不安全的环境之中。攻击者的一般攻击方法是利用软件中存在的漏洞去攻击用户,在用户主机上执行恶意植入的恶意代码,从而完成特定的攻击行为。

挖掘软件中潜在的缓冲区溢出漏洞,对提升信息系统的安全性具有重要意义。现有的软件漏洞挖掘技术中面向源代码的漏洞挖掘技术研究最早也最成熟,但面向源代码的软件漏洞挖掘技术仍存在很多不足[2]。由于漏洞不可能被消除,只能通过各种措施进行缓解[3]。因此,目前对漏洞攻击的防御策略主要是基于先验知识的被动防御,而且大多可以被攻击者绕过,防御效果不理想。其根本原因在于软件程序的同构性和运行环境的稳定性,指令集的稳定是运行环境稳定的重要因素。而随机化技术可以有效打破这种同构和稳定性的环境,以异构和随机的环境来应对未知的攻击。Pa X项目在2001年首先提出了ASLR(address space layout randomization)技术,2003年Gabriela等人提出了指令集随机化技术,2010年Georgios等[4]人对ELF文件格式的程序实现了指令集随机化。Bhatkar提出了数据随机化技术。这些技术有的已经在信息安全领域发挥了巨大作用,如ASLR技术;但有的技术则没有被利用,如指令集随机化技术。因为Georgios提出的这套技术通过对指令进行异或加密再使用虚拟机翻译执行,一方面开销很大,另一方面该技术假设在obj文件中指令与数据分离,目前只在ELF文件中基本实现这种指令集随机化。

本文提出一种基于Phoenix编译器的指令集随机化技术,该技术通过新生成的指令集来随机化程序中的指令,为程序提供了一个随机、动态和不确定的运行环境,实现了操作码层次的指令集随机化。外部注入代码与新指令集不兼容,即使成功注入攻击代码也无法正常运行,可能会导致拒绝服务但无法得到任何有用信息。实验表明该技术可以在低空间和时间开销的前提下有效地防御代码注入型攻击。目前已经利用该技术实现了X86架构下Windows系统程序的指令随机化,该技术同样可以适用于X86架构下Linux系统程序的指令随机化。

1 代码注入型攻击及防御策略

代码注入型攻击[5]是目前最常见而且破坏性很大的攻击,攻击者通过一定的方法将恶意代码注入到用户的进程,并通过溢出等手段改变程序正常的控制流,使程序执行恶意代码从而实现某种攻击目的。国内外学者对代码注入型攻击及其防御策略做了大量的研究工作[6,7,8]。目前最常见的代码注入型攻击分为栈溢出攻击和堆溢出攻击。文献[9]从C语言程序角度总结了栈溢出攻击的三种基本攻击模式。2000年,Solar designer第一个实现了堆溢出利用。2001年,Flake提出TEB的利用方法。2005年,Falliere[10]提出通过Rtl Delete Critical Section覆盖堆临界区结构的方法绕过防御。2008年,Hawkes[11]提出堆结构覆盖和LFH bucket/header覆盖等技术可以在一定程度上突破现有堆保护技术。

对栈溢出攻击的防御有在关键数据和缓冲区之间加入一个随机的canary字的Stack Guard[12]防御策略及其衍生出的防御策略;构建与普通栈隔绝的全局返回地址堆栈的Stack Shield防御策略;在栈帧中引入随机长度的填充区使攻击者无法准确定位函数返回地址或调用方函数EBP的防御策略。对堆溢出攻击的防御[13]有安全摘除链表检测链表完整性;在堆头部增加安全cookie;对PEB/TEB的地址做有限随机化;移除lookaside表和Free List[0];堆块元数据加密;动态改变堆分配算法;函数替换与指针编码等多种堆溢出攻击防御方法。

这些防御策略有共同的两个弱点:①在一定条件下,攻击者可以采用特定的攻击手段突破这些防御;②这些防御都有单一不变性。这就造成防御策略与被防御目标程序的绑定存在,攻击者一旦获取待攻击程序的二进制代码,就能够通过学习获得待攻击程序采用的所有防御机制。

2 基于指令集随机化的代码注入型攻击防御

代码注入型攻击向程序中注入攻击代码,并在软件漏洞被触发时改变程序控制流执行攻击代码。代码注入型攻击的成功需要有一个稳定的攻击环境,模块基址的改变或指令的变换都会在不同程度上影响攻击的成功率。本文提出了一种基于指令集随机化的代码注入型攻击防御思想,该思想是利用随机化指令集对obj文件中的指令进行随机改变,攻击者不了解这套指令集规则,使外部注入的代码与新的指令集不兼容,经过动态二进制分析平台翻译时正常代码被翻译为可执行代码而恶意代码则被翻译为乱码。与以往的防御策略相比,该防御思想打破了漏洞攻击所需要的稳态环境,每次编译都使用不同的指令集,实现了防御策略与被防御目标的分离,使攻击者很难攻击成功。该防御思想的原理如以下公式,其中f为指令随机化函数,source为程序源代码,rand为经过随机化的程序,f'为动态二进制平台翻译指令函数。恶意代码没有进过f函数的转化,直接用f'处理,被翻译为无用代码。

基于该主动防御思想,本文提出一种修改obj文件的指令集随机化技术。该技术利用新的指令集随机化改变编译器产生的obj文件中的指令而达到指令随机化的目的。为了准确定位指令在obj文件中的位置,需要利用Phoenix编译器在编译过程中提取出程序的汇编指令信息,并利用该信息与obj文件中代码段信息进行匹配,生成指令随机变换规则,如果匹配成功则为指令加上段偏移从而定位了指令位置。完成所有指令的匹配工作后,对obj中的指令按照所制定的规则进行变换,并将变换后的指令回写入obj。所有的obj文件经过链接后生成经过随机化处理的可执行文件,该可执行文件需要利用动态二进制分析平台启动,在一定指令变换规则的支持下将程序中经过随机变换的指令翻译回正常X86指令并运行程序。图1为指令集随机化流程图。在上述过程中,所用到的关键技术有源程序汇编指令信息的提取;制定指令变换规则;obj文件解析及指令定位;随机化程序执行。这些技术的实现将在下文进行叙述。

2.1 基于Phoenix的汇编指令提取

汇编指令提取主要是在Phoenix编译器编译目标程序的后期,即将程序信息写入obj阶段,提取出目标程序的汇编指令信息,为下一步定位obj文件中的指令位置做准备。

Phoenix是微软提供的一个编译器框架,用户可以通过Phoenix设计编译器及各种工具用于软件程序的分析、优化和测试。源代码经过Phoenix分析,被表示为IR(中间表示,Intermediate Representation)形式,Phoenix编译器和各种基于Phoenix的工具对程序后期的处理工作都是在IR层次上进行的。与其他编译器不同,Phoenix可以为微软支持的所有语言和平台生成二进制文件或MSIL代码。同时Phoenix提供了丰富的API接口函数,用户可以利用Phoenix提供的API函数开发自己想要的工具。图2为Phoenix编译器框架图。

与其他编译器相同,Phoenix对源文件进行编译会生成目标对象文件(obj文件),为了避免反汇编带来的不确定性,使指令随机化更加准确,本文提出了在obj文件中进行指令随机化的方法。为了精确定位指令在obj文件中的位置,需要通过Phoenix提供的API函数编写一个源程序汇编代码自动化提取插件,在Phoenix后期处理的Emission阶段(phase)之后插入一个汇编代码提取阶段Getasm阶段。根据提取出来的汇编代码结合obj文件信息可以准确定位各条指令的地址。

算法1

算法1利用Phoenix编译器提取程序的汇编指令,其中Find By Name()为找phase函数,Isert After()为插入phase函数,两个函数均为Phoenix编译器提供的API函数,file.asm为存取汇编指令信息的文件。Phoenix对程序分模块编译,Getasm为插入的phase,当执行到Getasm时开始汇编指令信息提取。算法中结构体Insn的定义如下:

2.2 obj文件解析及指令定位

obj文件为程序经过编译器编译生成的目标文件,包含程序中的指令、数据等信息。解析obj文件需要从obj文件中的代码段提取出段偏移、大小等信息,并结合已经提取出的指令信息定位指令在obj文件中的位置,进而根据变化规则完成指令随机化工作。

指令变换规则的制定需要满足以下几点条件:1)有效性。指令进行随机化后,在DynamoRIO进行翻译时会进行语义检查,如果语义错误将无法正常执行。2)细粒度性。随机化的粒度应尽可能细,粗粒度的防御策略已经很多,且容易被攻击者绕过。3)开销可控性。指令集随机化要求在增加安全的情况下控制开销,代价过大将使工作失去意义。为满足以上要求,本文采取对指令集分层随机化策略,经过对IA-32 Inter指令集中1099个指令进行筛选分类,将可随机化的指令组成一个集合ISRInsn。集合ISRInsn中有四个子集:Onebyte Insn、Twobyte Insn、Operate Onebyte、Operate Twobyte,分别表示单字节指令、双字节指令、操作码单字节长度相等指令、操作码双字节长度相等指令。Opercode Onebyte与Opercode Twobyte又可按照指令长度分成若干子集。表1为选取的部分随机指令分组表。

ISRInsn={Onebyte Insn,Twobyte Insn,Opercode Onebyte,Opercode T-wobyte}

目标对象文件(.obj文件)中包含了编译后的机器指令代码、数据,以及链接时所需要的各种信息,这些信息在obj文件中按照属性的不同以段(segment)的形式进行存储。机器指令被放在代码段(.text和.textx),全局变量和局部静态变量数据被放在数据段(.data)。本文通过解析obj文件映像头和段落头来获取段名、段落头数以及代码段的偏移大小等信息,为指令随机化做准备。图3为指令随机变换示意图。

算法2

输入:选取的随机指令、obj文件、asm文件

输出:isr.config

1)对指令按不同集合进行分组,并存入不同数组中;

2)对不同数组中指令的顺序进行随机化,得到顺序随机的指令数组;

3)对每一组指令进行双双配对存入一个结构体,并将所有指令压入vector容器中,写入指令规则rule.config之中;

4)解析obj文件:将obj文件映射到内存之中,根据obj文件格式读取obj文件中.text段与textx段,提取段名、段大小和段偏移等信息,分别存入两个链表List text与List textx;

5)读取.asm文件,并提取text、textx段中指令的偏移、操作码和汇编指令,存入结构体并压入vector容器Instruction_all中;

6)将Instruction_all中的指令与链表中节点进行匹配,若匹配上则为指令加上段偏移地址,若未匹配则进行下一个节点匹配,直至所有节点都被匹配,所有指令匹配结束压入一个map中,并将结果写入文件;

7)在obj中按照制定的随机变换规则对选取的指令进行随机变换,并将随机变换的指令回写入obj文件。

2.3 随机化程序执行

经过随机化处理的程序不能直接执行,需要利用动态二进制分析平台将被随机化的指令动态翻译回正常的X86指令。本文利用了DynamoRIO平台。

DynamoRIO可以在指令级别上对程序动态分析,采用代码缓存技术将程序代码拷贝到代码缓存,进而对目标程序模拟执行,在执行过程中修改目标程序的二进制代码,达到指令级分析的目的。本文对目标程序进行指令级插桩,在目标程序的地址范围内读取基本块中的每一条指令进行判断,如果是经过变换的指令则按照规则翻译回正常指令,如果不是则读取下一条指令,直到所有指令被翻译回正常指令。

随机化程序执行流程如下:

1)利用动态二进制平台启动目标程序;

2)读取随机指令变换规则;

3)主模块加载时(event_module_load)获取主模块的起始和结束地址;

4)读取当前基本块的当前指令,根据指令操作数判断该指令是否为指令变换规则中的指令,如果是则读取出变换目标指令操作码,如果不是则读取下一条指令;

5)根据目标指令操作码创建目标指令,并获取目标指令的源操作数与目的操作数;

6)进行指令替换;

7)循环执行(4),直至所有指令被翻译为正常指令。

2.4 系统设计与实现

为验证该技术的可行性,本文设计了一套原型系统。图4为系统设计原理图。该系统主要分为四个模块:信息提取模块、指令随机变换模块、随机策略支撑模块、动态翻译模块。

3 实验过程及结果分析

通过实验验证原型系统的有效性,并分析经过随机化后程序的时间开销与空间开销。实验条件:两台装有XP系统的虚拟机A、B桥接互连。A主机用作攻击者主机,安装metasploit 3和python2.7;B主机用作被攻击者的主机,安装DynamoRIO。

实验一对Miniweb植入shellcode打开计算器

在Miniweb源码中构造一个缓冲区溢出漏洞,并用metasploit构造攻击脚本进行攻击。配置metasploit攻击载荷参数:windows/exec(执行任意的cmd命令),测试其启动计算器的功能。执行exploit命令,Miniweb程序被关闭,弹出了计算器窗口,攻击成功。经过系统防护后,用DynamoRIO平台运行,Miniweb崩溃。

实验二利用Miniweb上传木马测试

使用相同的攻击脚本对Miniweb进行攻击。生成灰鸽子服务程序,在meterpreter提示符下完成灰鸽子服务端的上传,执行木马程序。打开灰鸽子控制端程序,点击自动上线,攻击成功,退出meterpreter。使用系统的防护措施后,攻击失败。

图5、图6为Miniweb经过指令随机化处理前后指令片段对比,经过随机化处理后Miniweb程序的指令按照指令变换规则进行了随机变换。

结果分析:

经过原型系统随机化过的软件,其安全性能得到了很大的提高,可以防御绝大多数的代码注入型攻击,该系统为软件提供了一个随机、多态和不确定的运行环境,打破了各类漏洞利用所需要的稳态环境,实现了一种主动式的软件抗攻击技术。通过大量测试表明该系统能够防御大多数代码注入型攻击,表2为部分测试结果。经过随机化处理后软件的时间开销与空间开销会相应增大,图7、图8为四种软件经过随机化处理前后时间和空间开销对比图。以Miniweb为例进行说明,Miniweb程序指令条数在四种软件中最多,其被随机化的指令条数最多,在动态解释执行时翻译指令消耗时间较长,所以时间和空间开销都较大。Miniweb在执行cmd和上传木马两种不同的攻击时,上传木马的攻击行为较为复杂,其时间开销与空间开销较大。由此可知,随机化后软件的开销会受其指令条数的影响,指令条数多的软件,其时间空间开销较大。同一软件受到的攻击行为越复杂,其时间空间开销越大。总体来说,增大的开销在软件运行可接受的范围内。

注:运行时间、内存消耗效率是指本系统处理后的软件运行时间、内存消耗值与未经本系统处理软件运行时间、内存消耗值的比值

4 结语

本文提出了一种指令集随机化技术,该技术在编译层对程序指令进行随机化改变,为软件构建出一个随机、动态和不确定的运行环境,打破了各类漏洞利用所需要的稳态环境,对代码注入型攻击不再关心代码如何注入到进程,而是阻止恶意代码被执行从而对软件进行防护。设计并实现了一套原型系统,并通过大量实验证明,该技术可以成功防御大部分代码注入型攻击,改变了被动防御局面实现了主动防御。

栈随机化 篇2

其中A代表评价结果, C1、C2分别为两组样本的平均成本, E1、E2分别为两组样本的平均疗效。相应A代表两组样本最终的成本-效用指标评价结果。一般国内文献均根据此样本计算结果给出药物经济学评价的结论。但是, 根据统计推断的原理, 如果仅关心进入研究的样本人群评价结果, 分析到此是可以接受的。想要给出样本人群背后所代表的的总体人群的结论, 这个结果是不科学的, 因此需要根据样本人群去推断总体人群的结果。

常用的统计推断包括参数检验和非参数检验。前者要求明确数据的分布、构建概率分布、完成统计推断;后者对数据的分布无任何要求。明确成本-效用指标的统计分布比较麻烦, 因此笔者检验采用非参数检验的方法完成统计推断的工作。随机化检验是比较理想的选择。

随机化检验, 也称为排列检验[1], 是最早用以检验两个总体均值差的方法之一。虽然这种方法本质上对数据的分布没有任何要求, 但因涉及大量的计算, 所以直到最近才真正可行。它指的是从所有结果中随机产生部分结果。而不是采用所有的可能结果进行计算。具体操作如图1, 最后根据结果是否落在拒绝域决定是否拒绝原假设。下面根据某临床研究数据实现以上过程。

1 资料来源及数据特征

本研究数据来源于北京中医药大学药物经济学研究所某关于心血管疾病的课题, 从中随机抽取102份样本, 其中使用A、B两种治疗方案的样本分别为70份、32份, 见表1。

2 数据分析及结果

本研究数据分析基于SAS 9.1完成, 分析流程见图1, 程序如下。

以上程序中group为分组变量, f1、f2分别代表效用及成本, col1、col2分别代表两种治疗方案的成本-效用比, f3代表两种治疗方案的成本-效用比差值。原始数据效用、成本信息见表2、3, 原始数据成本-效用比分析结果见表4, 随机抽样500次计算结果见表5。

根据表4和表5的计算结果, 原始研究数据的成本-效用比组间差值在成本-效用比差值95%CI范围内。设定可接受一类错误为双侧0.05, 据此分析结果, 尚不能认为两种不同用药方案成本-效用比存在差异。

注:组间分配采用不放回随机抽样, 每组例数与原试验一致, 总计算500次 (根据随机化检验原理, 应该抽样102!/ (32!X70!) 次, 考虑本论文旨在说明一种方法, 故仅计算500次) 。排序后双侧95%分位数分别为12位、488位 (精确计算为12.5, 475.5, 保守估计采用12, 488)

3 讨论

本研究假设原始数据来源于随机试验, 另外计算过程中未考虑到极值问题, 其计算过程并不完美。但为药物经济学统计推断提供了一个思考的方向。对于非随机化的观察性研究数据, 一些与评价指标相关的因素可能在组间分布不均衡, 其因果推断不像随机化试验可信度高, 此时建议在完成倾向评分匹配[2,3]的基础上, 再进行随机化检验不失为一种可以研究的方向, 比如本研究的数据中患病时间存在组间差异, 可以先根据倾向值匹配的原理进行组间匹配, 之后在完成随机化检验。有学者提出[4]采用自主法估算区间, 与本文中提出的方法具有一定的相似性, 读者可自行选择合适的方法。另有学者[5]研究提出其他区间估计方法, 如BOX法、椭圆法、Taylor级数扩展方法。但在计算机广泛应用的今天, 采用重复抽样的方法计算区间相对比较简单。

摘要:目前, 国内关于药物经济学评价大多采用点估计的方法简单对比不同用药方案的评价指标, 但是基于统计推断的理论, 这种简单处理并不能反映研究人群总体的比较结果。本文将随机化检验应用于药物经济学评价中, 能在一定程度上解决药物经济学疗效评价的问题。

关键词:随机化检验,统计推断,药物经济学评价

参考文献

[1]William Navidi.统计学—科学与工程应用[M].北京:清华大学出版社, 2007:449-449.

[2]郭申阳.倾向值分析:统计方法与应用[M].重庆:重庆大学出版社, 2012:84-109.

[3]李智文, 任爱国.倾向性评分在SAS软件中的实现[J].中国生育健康杂志, 2010, 21 (5) :320-322.

[4]谢颖, 宗欣, 孙丽华.非参数Bootstrap法在成本-效果置信区间估计中的应用[J].中国药房, 2010, 21 (22) :2027-2029.

栈随机化 篇3

根据大数定理, 知道 “当试验次数足够多时, 事件出现的频率无穷接近于该事件发生的概率”, 根据中心极限定理, “ 大量统计 独立的随机 变量的平均 值的分布 趋于正态分 布 ” , 因此采用蒙特卡洛方法, 通过构造概率模型进行数据的分析在工程和科学实践中应用广泛。 但是现有的计算机程序设计语言都仅提供生成一个等概率的随机序列方法, 无法满足工程和科学上对特殊分布的需求, 尤其是对正态分布这样普遍的分布。

通过区间映射方法, 通过划分不同的映射区间大小, 达到不同区间具有不同的生成概率, 整体趋向于正态分布的统计概率函数。

2 算法思想

2.1 理论基础

以一维正态分布为例若随机变量X服从一个位置参数为 μ、σ 尺度参数为的概率分布, 记为:

则其概率密度函数为:

不同的位置参数和尺度参数的正态分布如图1所示。

其中 μ=0并且 =1的分布被称为标准正态分布, 概率密度函数简化为:

一般正态分布和标准正态分布满足如下关系:

如果X~N那么关于X的线性变 换一定服从标准正态分布N(0,1)。 即:

若做线性变换令则 Y~N(0,1)。

因此, 只论述标准正态分布的随机化实现方法, 非标准正态分布先产生符合标准正态分布的随机序列,之后通过线性坐标映射X=σ*Y+μ 就可以得到非标准正态分布的随机序列。

2.2 产生符合正态分布统计规律的原理

通过逐步划分, 渐次逼近的方法, 逐步逼近正态分布的产生概率。 因为正态分布函数是连续的, 可以采用阶梯函数逐渐逼近正态分布函数。 如图2所示。

图2中蓝线表示正态分布, 红线和紫线分别表示采用不同划分精度的阶梯函数逼近的效果, 从图2中可以看出, 紫线的逼近效果应该会好于红线的逼近效果。 如果将阶梯函数的单位长度设置的越来越小, 最终阶梯函数将会和正态分布函数完全一致。 因此问题就转换为如何产生符合阶梯函数生成概率的随机序列。

2.3 生成阶梯函数随机序列的原理

假设阶梯函数为f(x), 表示随机数的概率密度函数, x轴上点x1,x2,x3,x4是等间距的, f(x3) =f (x2) =y2, f (x4) =f(x1) = y1。 如图3所示 。

现在根据以上条件, 求出满足阶梯状概率密度函数的随机序列。

因为在x2,x3区间内生成的随机数的概率要大于其他区间的概率, 因此, 我们需要将x2,x3区间映射到新的区域。 那么x2,x3需要映射 的区域大 小应该为 :

所以可以继续表示为:

这样, 就可以得到, 在区间间隔相同的条件下, 映射后的区间长度和区间上概率密度函数的值成正比。 同理, 可以求出x3,x4映射后的区间长度, 最终结果为:

这样 , 假设对 [x1,x4] 区间范围映 射到区域 [k1,k2]。 则每个小区间分别对应的映射区域为:

在 [k1,k2] 范围内采用等概率随机算法生成随机序列, 根据随机点落在不同的区域, 对应不同的概率区间。

2.4 一般的梯度函数逼近正态分布公式

定义正态分布的定义域为 [m1,m2] ,采用梯度函数逐步逼近的单位步长为k, 全体定义域映射后的范围是 [D1,D2]。 因为标准正态分布关于y轴对称, 因此, 只计算x轴负半部分的映射关系就可以了, x轴正半部分是一样的。

则由以上 条件知 , 阶梯一共 有 (m2-m1) /k个区间 , x轴负半部 分的区间 范围是 [ 1, ( m2 -m1) /2k] , 对任意的假设区间1的映射范围为L 1 , 则

区间n的映射区间为:

进一步可求得:

将 (9) 式带入 (8) 式中, 整理后就可以得到每个映射区间后的起止范围。

区间n的起止范围为

2.5 正态函数的离散化取值范围和梯度函数步长值的选取

因为正态函数的取值域是, 计算机编程中区间映射要是一个确定范围才可以进行变换和映射。 实际编程中采用了3sigma或6sigma原则, 即定义正态函数的取值范围为 [3sigma,3sigma] 或 [-6sigma,6sigma] 因为正态 分布在两个 区间范围内的概率分别为是0.9973和0.99, 其中3sigma也是在数学统计中普遍接受的原则。 梯度函数的步长值选取也不是越小越好, 因为计算机编程过程中, 越小的步长值也就意味着在计算 (1) 式的时候, 定义域的两边会出现一个极小值除以一个极小值的情况, 计算结果会产生很大的误差。

2.6 从映射区间映射回正态分布的原定义域方法

采用均匀分布在映射区域生成随机序列后, 找到映射区域对应的原定义域区间, 从原被映射区间中随机均匀分布产生一个随机点组成的随机序列就是所求的满足正态概率密度函数分布的随机序列。

3 实验结果与分析

3.1 实验结果

(1) 当取3σ 为定义域时 , 取步长值为0.1时 , 实验值和 理论值的误差在0.27%。 取步长值为0.01时, 实验值和理论值的误差在0.27%。

(2) 当取6σ 为定义域时 , 取步长值为0.1时 , 实验值和 理论值的误差降低到2.03E-9。 取步长值为0.01时, 实验值和理论值的误差在1.97E-9。

(3) 随机点分别 取1w,10w,100w个点 , 步长值为0.1时生成的概率密度函数图和标准正态分布的比较。

3.2 实验结果分析

(1) 无论是取0.1还是0.01的步长值 , 实验值和理 论值的误差都是非常接近的, 表现了生成算法的稳定性。 而较低的误差率, 也体现了算法的可靠性和准确性。

(2) 随着随机 点数的增加 , 生成点的 概率密度 函数符合 大数定理和中心极限定律, 越来越趋近于正态分布, 这说明生成的随机点的确符合正态分布的统计学规律。

3.3 实验误差分析

在实验中, 为了使得计算机能够离散化, 采用的是3σ 原则, 将正态分布的定义域定义为 [-3σ,3σ] 之间, 这使得和理论值是有一定的差别的, 实验中进一步采用6σ 原则, 将正态分布的定义域定义为 [-6σ,6σ], 误差率下降明显。 但是并不是将定义域的取值越大越好, 步长值越小越好, 正态分布在轴的两侧趋近于零, 过大的定义域取值将大大增大计算的时间复杂度, 过小的步长值将会影响到计算的精确度。 实际应用中建议根据需要选取步长值为0.1或0.01, 定义域3σ 或6σ 即可。

4 结语

栈随机化 篇4

本文介绍了缓冲区溢出的基本原理及主要的防御方法,其中重点分析了地址空间随机化技术在Linux系统中的实现,并针对这一防御技术,研究如何绕开其防护的缓冲区溢出攻击方法,并作了相关的理论分析和实际测试。

1 缓冲区溢出

1.1 缓冲区溢出攻击原理

缓冲区溢出是指:写入缓冲区的数据量超过缓冲区的设计大小,溢出的数据覆盖了相邻存储单元中的数据。攻击者通过溢出缓冲区将恶意代码注入内存,使进程运行时跳转并执行恶意代码来进行攻击[3]。缓冲区溢出攻击主要分为以下几类:栈溢出、堆溢出、格式化字符串溢出和整型变量溢出等,其中以栈溢出最为常见。

在Intel 80×86体系结构中栈位于高地址区域,且向低地址方向增长。栈帧在内存中的分布结构如图1所示,其中,调用方EBP(栈基地址指针)存放了函数调用方的栈底地址,函数返回值存放了函数结束后的返回地址。由于新创建的数据总是位于内存的低地址区域,当用户向低地址缓冲区写入过多数据时,就会造成数据溢出,从而篡改高地址内存中的关键数据。如果写入的数据是攻击者精心构造的恶意代码shellcode,返回地址等指针被覆盖成了指向shellcode的指针,当调用该指针时,就将跳转并执行shellcode,从而改变进程的行为,达到入侵的目的。

1.2 缓冲区溢出攻击防御

针对缓冲区溢出攻击的防御方法归纳起来有:编译保护、安全库函数、缓冲区不可执行和随机化方法等。

编译保护是通过扩展编译器以防止函数的返回地址被修改来实现栈保护。通常是在返回地址前放置一个标志字或建立一个影子栈,在函数返回前查看是否有溢出存在。目前已有不少的补丁可供使用,如Stack Guard和Stack Shield。但这种方法只局限于对栈的保护。

C标准库中的函数一般不进行参数验证,通过重写这些函数使其进行参数验证,增加一些安全检查机制可以有效阻止缓冲区溢出攻击。如Libsafe对常见的字符串操作函数进行封装[4],在调用这些函数时先进行边界检查,一旦目标缓冲区不能容纳源字符串则终止程序。针对Libsafe只保护栈的不足,Avi-jit等提出Libsafe Plus[5],通过抽取程序的调试信息,实现对全局变量、栈变量和堆变量的边界检查。

缓冲区不可执行包括栈不可执行和数据段不可执行。攻击者通常是将恶意代码植入溢出的缓冲区中,只要让这些可写的缓冲区不可执行,就能防止恶意代码控制程序。采用这种技术的典型例子有Linux内核补丁Pa X(Page Exec)[6]。它通过不可执行页实现了不可执行栈和不可执行堆。不可执行缓冲区对于需要注入可执行代码这类攻击的防范是高效的,但无法阻止像return-into-libc这种无须注入代码的攻击。

现有的用于防范针对内存攻击的技术或者系统只能防御某一特定方式的攻击,而且要将这些技术或者系统集成在一起很困难。操作系统的安全防护机制对缓冲区溢出漏洞利用有很大影响。如果能在操作系统层检测和阻止缓冲区溢出攻击,将大大提升系统的安全性。因此研究人员提出了随机化方法对系统进行保护,主要有指令随机化和地址空间随机化。

指令随机化是指编译时对可执行程序的机器码进行加密,在指令执行前,对每条加密的指令进行解码。这个过程使得攻击者植入的恶意代码不能完成预定的功能,通常会导致程序崩溃。但这种方法存在因使用虚拟机导致负荷过重等问题[7]。

地址空间随机化ASR(Address Space Randomization)技术是近几年发展起来的一项比较有效的防御缓冲区溢出攻击的技术,由于它的独到之处,Linux、Free BSD和Windows Vista等主流操作系统都已采用了该技术。

2 Linux地址空间随机化技术的实现

基于缓冲区溢出漏洞的攻击需要事先熟悉进程的地址空间,从而将程序的执行流程跳转到攻击代码的位置。ASR技术通过对操作系统内核或C库的修改,使进程加载到内存的地址随机化,使得攻击者无法将程序的执行流程跳转到预期位置,从而阻止进程执行攻击者预先设置好的攻击代码。攻击者要想控制系统,需要修改返回地址或指定地址为指定值。地址随机化后,这些指定地址或者指定值都将无法事先确定,攻击者只能猜测该地址,所以不能保证能正确地跳转到攻击代码的位置,从而有效地降低攻击者攻击成功的概率。

2.1 Linux可执行目标文件的加载过程

在Linux系统中可以通过execve系统调用启动加载器。加载器为新进程创建一组新的代码、数据、堆和栈段。新的堆和栈段被初始化为零。通过将虚拟地址空间中的页映射到可执行文件的页大小的组块(chunks),新的代码和数据段被初始化为可执行文件的内容。最后,加载器跳转到_start地址,它最终会调用应用的main函数。除了一些头部信息,在加载过程中没有任何从磁盘到存储器的数据拷贝,直到CPU引用一个被映射的虚拟页时,操作系统才会利用页面调度机制将页面从磁盘传送到存储器。

当加载器运行时,它创建的存储器映像如图2所示。在Linux系统中,代码段总是从0x08048000处开始。数据段是在接下来的下一个4KB对齐的地址处。运行时堆在接下来的读/写段之后的第一个4KB对齐的地址处,并通过malloc调用向高地址增长。开始于地址0x40000000处的段为共享库保留。用户栈从地址0xbfffffff处开始,并向低地址增长。从栈的上部开始于地址0xc0000000处的段是为内核的代码和数据保留的。

2.2 Linux中的地址随机化

自从Linux 2.6.12版本后,地址随机化技术已经默认在Linux内核中启用。在Linux 2.6.27下的测试结果如图3所示。

从图3中可以看出,栈、堆和共享库的加载地址是随机的。通过比较多次运行的结果可以判断,对于32位系统,栈基地址的第4-23位共20位是随机的,堆基地址的第12-27共16位是随机的,共享库基地址的第12-27位共16位是随机的。

Pa X是较成熟的ASR技术,它通过为Linux内核打补丁,在进程加载时,对栈基地址的4-27位共24位进行随机化,对包括主程序映象、静态数据区、堆这一连续区域的基地址的12-27位共16位进行随机化,对共享库加载地址的12-27位共16位进行随机化。再加上可写页不可执行技术,Pa X能大大降低攻击成功的概率。TRR通过修改进程加载器来实现ASR,而无需修改系统内核。与Pa X相比,TRR增加了对全局偏移表GOT的随机化,在进程加载时将GOT移动到新的位置,并用二进制代码修改工具修改代码段中的过程链接表PLT,以阻止修改GOT函数指针指向恶意代码的攻击。这一类ASR实现方案对栈、堆、主程序代码段以及共享库等在进程空间的基地址进行了随机化,粒度较粗、实现简单、额外开销较小,目前得到了广泛的应用。它们的缺陷主要在于只随机化了基地址以及使用的随机空间不大,可以被暴力破解和实施相对地址攻击。

2.3 栈随机化的实现

加载ELF可执行文件的函数是load_elf_binary()[8],它把page指针数组指向的内核页面以及可执行文件、解释器的部分区段映射到用户空间,并设置用户空间栈上的argc、argv、envp变量和解释器将用到的辅助向量,它调用的setup_arg_pages()函数形式为setup_arg_pages(bprm,randomize_stack_top(STACK_TOP),executable_stack);其中,STACK_TOP为用户空间的顶端,一般等于0xc0000000。randomize_stack_top()的主要代码实现如下:

首先判断内核是否开启了ASR保护,如果开启则调用get_random_int()获得一个随机数,并和STACK_RND_MASK(0x7ff)相与后左移PAGE_SHIFT(12)得到random_variable,最后将stack_top按页边界对齐后减去random_variable,得到最终的stack_top值。由此可以推出stack_top可能的最小值为0xc0000000-0x7ff000=0xbf801000。

其中,MAX_ARG_PAGES和PAGE_SIZE的值分别为32和4096,即参数的总长度不得超过32个页面。通过将sp指针减去一个随机数除8192的余数后,末尾四位取0,再进行PAGE_ALIGN,得到最终的stack_base值。最后setup_arg_pages函数将page指针数组指向的内核页面映射到用户空间中stack_base开始的区域。

上述分析可以得出:1)栈地址的第4-23位是随机的,页内偏移(0-11位)也是随机的。2)当向程序传递相同的环境变量时,即使stack_base不是固定值,但环境变量字串在页内的偏移是一个固定值。3)因为stack_base的最小值不会小于0xbf7df000,所以环境变量字串的地址总是高于0xbf7df000。

3 针对ASR防护的缓冲区溢出攻击方法

3.1 暴力破解

由于程序加载的位置不再固定,因此使用缓冲区溢出攻击程序成功的概率将大大降低。但由于使用的随机空间不大,通过一定次数的暴力破解后仍有可能成功。此时栈溢出攻击成功的概率计算如下。其中,L(v)表示v的长度。

1)shellcode在栈内变量buf中

p=(L(buf)-L(shellcode))/(L(random_stack_range)-L(shellcode)),

若L(buf)=256,L(shellcode)=25,L(random_stack-range)=1M,则p=0.02%。

2)shellcode在环境变量中

环境变量地址头8位是固定值bf,末12位通过getenv()函数再微调后获得,中间12位的范围是7df~fff,这是一个不大的区间。

p=1/(L(random_env_range)-L(shellcode))),

若L(random_env_range)=432,L(shellcode)=25,则p=0.24%。

3.2 转向非随机化区域

Linux操作系统默认采用了ASR机制后,它的栈,堆,共享库的加载地址是随机的,但是仍有些区域是非随机的,如text段、data段和bss段。因此可以通过覆盖栈中的返回地址使程序跳转到这些地方。

text段存放着程序代码,它是只读的,任何向其写入的操作都会被禁止,因此无法将shellcode放在其中。但可以用指向text段的另一个合法地址的指针覆盖返回地址,从而控制程序流程。bss段中存放的是未初始化的全局变量和静态变量。data段存放的是已初始化的全局变量和静态变量。如果程序中存在strcpy(localbuf,input);及strcpy(globalbuf,localbuf)语句,那么输入字符串input会覆盖局部变量localbuf,并最终覆盖全局变量globalbuf,又因为globalbuf的地址可以通过gdb调试确定,所以通过构造如图4所示的输入串就会控制程序执行shellcode代码。

3.3 return-into-libc

当设定栈不可执行后,shellcode无论放在栈的什么地方都基本无用,因此这种防御方法可以阻止大部分的攻击。在Linux中,可以通过Pa X设定栈不可执行,而return-into-libc方法可以避开这样的防护对策。return-into-libc主要从两方面突破Pa X的防护:1)通过伪造栈帧和利用连续的系统调用和库函数调用来构造溢出环境,这是因为系统调用和库函数所在的内存区是可执行的,然后在进程的内存空间中寻找一个非数据段的可执行空间来存放shellcode,最后使进程跳转到这一地址执行shellcode。2)针对库函数的随机定位,通过使用动态连接器dl-resolve()的接口即动态地址解析函数rtld,在溢出执行的过程中动态地决定函数的真正地址。

3.4 相对地址攻击

现有的ASR技术一般只随机化了基地址,可以被实施相对地址攻击。Tyler Durden针对Pa X只修改了基地址而没有修改主程序代码中语句的相对地址的漏洞[9],提出了一种攻击方法。因为Pa X只对主程序代码地址中12-27位进行了随机修改,所以代码段中特定代码的页内地址与没有采用Pa X的系统中的页内地址相同,因此可以通过覆盖存在溢出漏洞的函数的返回地址的最后一个字节(页内地址的低8位),使其跳转到本页内call或printf之类的指令,再通过格式化字符串攻击的方法,逐步获取共享库加载的基地址,实现return-into-libc攻击。

利用栈内数据间的相对偏移量不变这一特点也可实施攻击。如果知道进程的栈底地址,利用相对偏移量就可以计算出栈内其它变量的地址。由于stat文件对每个用户都是可读的,因此栈底地址可以从/proc//stat文件的第28项记录获得。一些守护进程或是需要等待用户输入的交互式进程很容易被这种攻击技术利用。一个简单的示例如图5所示。

服务端代码server.c中存在可利用的漏洞:strcpy(writebuf,str);首次运行程序时,通过gdb获得writebuf的地址,并通过cat/proc/`pidof server`/stat|awk‘{print$28}’命令获得stack_bottom的地址,然后计算offset=&stack_bottom-&writebuf=1496,最后再次运行程序,结果如图6所示。在客户端向服务端发起连接后,攻击者就能获得服务端的root shell,实现权限由普通用户到root用户的提升。

4 小结

本文重点介绍了地址空间随机化技术在Linux系统中的实现,以及如何绕过该技术保护的缓冲区溢出攻击方法。地址空间随机化技术是一种试图阻止各种内存攻击的有效技术。尽管它能有效降低缓冲区溢出攻击成功的概率,但由于随机化空间不够大、随机化粒度不够细等原因,使其不能完全阻止攻击。而细粒度的地址空间随机化又需要对程序内部结构进行较大的修改,这将导致兼容性差而得不到广泛应用。找到易于实现的细粒度随机化方法可能是ASR技术未来的研究重点。同时把ASR技术同其它的安全防护机制有效结合,可以构建出一套完整的缓冲区溢出防御体系,提高系统的安全强度。

摘要:缓冲区溢出攻击是一种被广泛利用并危害严重的攻击方式,已经成为计算机系统安全亟待解决的重要问题。在分析缓冲区溢出攻击原理的基础上,给出了主要的防御方法,重点探讨了Linux系统下地址空间随机化防御方法的实现,研究了如何绕过其防护的缓冲区溢出攻击方法,并对其防护效果进行了分析。结果表明,地址空间随机化技术能有效降低缓冲区溢出攻击成功的概率,但不能完全阻止攻击。

关键词:缓冲区溢出,Linux,地址空间随机化,攻击,防御

参考文献

[1]SANS Institute.Top 20 security vulnerabilities[EB/OL].http://www.sans.org/top20/.

[2]阎雪.黑客就这么几招[M].北京:北京科海电子出版社,2002.

[3]Forst J.C.,Osipov V.,Bhalla N.,et al.Buffer overflow attacks:detect,exploit,prevent[M].Rockland:Syngress Press,2005.

[4]A.Baratloo,N.Singh,T.Tsai.Transparent run-time defense against stack smashing attacks[C].Proceedings of 2000 USENIX AnnualTechnical Conference(USENIX'00).California:Usenix Association,2000:251-262.

[5]Kumar Avijit,Prateek Gupta,Deepak Gupta.TIED,LibsafePlus:Tools for runtime buffer overflow protection[C].Proceedings of the13th Conference on USENIX Security Symposium.Berkeley:Usenix Association,2002:191-206.

[6]PaX[EB/OL].http://pageexec.virtualave.net.

[7]Gaurav S.K.,Angelos D.K.,Vassilis Prevelakis.Countering code-injection attacks with instruction-set randomization[C].Proceedingsof the 10th ACM Conference on Computer and Communications Security.New York:ACM Press,2003:272-280.

[8]Hackisle.突破ASLR保护和编译器栈保护[EB/OL].http://blog.chinaunix.net/u3/102108/showart_2025891.html.

上一篇:血清过敏原检测下一篇:房地产的经典广告