空间格局随机化ASLR
2010-01-27 20:39
183 查看
1.概述
在前面安全编码实践中我们介绍过GS编译选项和缓存溢出,以及数据保护DEP。首先,缓存溢出的直接后果就是可能导致恶意代码的远程执行,于是编译器提供了GS保护。但是,GS选项有自身的局限,存在若干方法可以绕过GS选项的保护。于是进一步,操作系统提供了数据执行保护,即DEP,以及与之对应的NXCOMPAT编译选项。
那么是不是现在我们就可以高枕无忧了?在安全领域中,系统的攻防是一个不断发展进化的过程。DEP提出后,就出现了针对DEP的Ret2libc攻击手段。这一点我们曾在介绍DEP的安全编码实践文章的最后简单提及过。
ASLR(AddressSpaceLayoutRandomization),地址空间格局的随机化,就是用来防范Ret2libc攻击手段的另一个重要的安全特性。那么,什么是Ret2libc攻击,ASLR的原理是什么,开发人员如何使用这个安全特性,就是我们这篇文章要探讨的内容。
2.DEP和Ret2libc攻击
2.1DEP对堆栈溢出的保护
在栈溢出介绍中提及到Windows体系结构下函数堆栈布局(地址从高向低)如下:
表1:Windows系统的函数堆栈结构
如果发生堆栈溢出,恶意代码通过覆盖在堆栈(stack)上的局部变量,从而修改函数的返回地址,而导致恶意代码执行。下面是这类攻击方式的堆栈结构的一个典型例子。
表2:堆栈溢出时的堆栈结构
当DEP保护机制被使用后,由于恶意代码是存放在系统的数据页面(堆栈页面上),那么函数返回时,指令寄存器EIP将跳转到恶意代码的入口地址。此时该页面是非可执行的(non-executable),于是DEP就会触发系统异常而导致程序中止。
2.2Ret2libc攻击
在上述的DEP保护机制中,可以看到关键是在函数返回时EIP跳转到了非可执行页面时被DEP检测到。那么Ret2libc的攻击原理是,攻击者设定的函数的返回地址并不直接指向恶意代码,而是指向一个已存在的系统函数的入口地址。由于系统函数所在的页面权限是可执行的,这样就不会触发DEP异常。
那么,攻击者应该将EIP控制指向那个特殊的系统入口函数?一个例子是在Unix系统下,libc是一个共享的C动态执行库,里面有许多非常有用的函数,例如system函数。它的定义如下:
intsystem(constchar*string);
函数system()可通过运行环境来执行其它程序,例如启动Shell等等。那么,攻击者就可以通过构造以下的堆栈结构【1】:
表3:Ret2libc攻击的堆栈结构
这样,当发生堆栈溢出的函数返回时,EIP跳转到system函数。因为system函数本身就是可执行的,这时不会产生DEP异常。攻击者通过构造system函数的调用参数来可以启动其它程序。在攻击过程中,函数返回到libc库(returntolibc)是关键,这也就是Ret2libc名字的来由。
细心的读者也许已经发现,在表3中,没有任何恶意代码被插入。攻击者虽然可以通过system或者其它系统函数来执行很多敏感的操作,但在多数情况下,还是更希望可以执行自身定制的恶意代码。如何可以做到这一点?于是在最初的Ret2libc的攻击方式的基础上,又发展出特别针对Windows系统攻击的手段。它的原理是通过VirtualProtect函数来修改恶意代码所在内存页面的执行权限,然后再将控制转移到恶意代码。
VirtualProtect是Windows系统kernel32.dll提供的函数,其功能是修改调用进程所在虚拟地址空间(virtualaddress)的内存区域的保护权限。它的定义如下:
BOOLWINAPIVirtualProtect(
__inLPVOIDlpAddress,
__inSIZE_TdwSize,
__inDWORDflNewProtect,
__outPDWORDlpflOldProtect
);
攻击者构造以下的堆栈结构【2】来调用VirtualProtect:
表4:使用VirtualProtect攻击的堆栈结构
首先,当发生堆栈溢出的函数返回时,EIP跳转到VirtualProtect函数。注意到这里攻击者特别构造将恶意代码的入口地址作为VirtualProtect函数退出时的返回地址。由于在VirtualProtect的执行过程中,恶意代码所在的页面被修改为可执行权限,这样当VirtualProtect返回时,EIP再跳转到恶意代码时就不会触发任何DEP异常。
除了使用VirtualProtect函数,攻击者还可以使用其它函数,例如NtSetInformationProcess等等。
3.ASLR和/dynamicbase链接选项
在上面对Ret2libc攻击方式的介绍中,我们看到最为关键的一点是攻击者事先预知了特定函数,如system或VirtualProtect的入口地址。在WindowsXP或Windows2000上,这些函数的入口地址是固定的,即攻击者事先可以确定的。
在WindowsVista中引入了ASLR安全特性。它的原理就是在当一个应用程序或动态链接库,如kernel32.dll,被加载时,如果其选择了被ASLR保护,那么系统就会将其加载的基址随机设定。这样,攻击者就无法事先预知动态库,如kernel32.dll的基址,也就无法事先确定特定函数,如VirtualProtect,的入口地址了。
ASLR是系统一级的特性。系统动态库,如kernel32.dll,加载地址,是在系统每次启动的时候被随机设定的。
下面是一个简化的ASLR演示程序【3】。
//aslr.cpp:DemothedynamicbaseofDLLsduetoASLR
//
#include"stdafx.h"
#include<windows.h>
#include<stdio.h>
voidfoo(void)
{
printf("Addressoffunctionfoo=%p/n",foo);
}
int_tmain(intargc,_TCHAR*argv[])
{
HMODULEhMod=LoadLibrary(L"Kernel32.dll");
//Note—thisisforreleasebuilds
HMODULEhModMsVc=LoadLibrary(L"MSVCR90.dll");
void*pvAddress=GetProcAddress(hMod,"LoadLibraryW");
printf("Kernel32loadedat%p/n",hMod);
printf("AddressofLoadLibrary=%p/n",pvAddress);
pvAddress=GetProcAddress(hModMsVc,"system");
printf("MSVCR90.dllloadedat%p/n",hModMsVc);
printf("Addressofsystemfunction=%p/n",pvAddress);
foo();
if(hMod)FreeLibrary(hMod);
if(hModMsVc)FreeLibrary(hModMsVc);
return0;
}
这段程序的目的是输出kerner32.dll和msvcr90.dll的基址,loadlibrary和system函数的入口地址,以及应用程序本身一个函数foo()的入口地址。
使用ASLR非常简单。从VisualStudio2005SP1开始,增加了/dynamicbase链接选项。/dynamicbase选项可以通过ProjectProperty->ConfigurationProperties->Linker->Advanced->RandomizedBaseAddress,或直接修改linker的命令行编译选项即可。
在VisualStudio2008环境,用Win32ConsoleApplication类型,编译链接演示程序。注意,如果使用VisualStudio2005SP1的话,需要将msvcr90.dll更改为msvcr80.dll。
如果程序没有使用ASLR功能的话,在WindowsVista下运行。输出的结果是:
Kernel32loadedat763F0000
AddressofLoadLibrary=7641361F
MSVCR90.dllloadedat671F0000
Addressofsystemfunction=6721C88B
Addressoffunctionfoo=00401800
重启系统
Kernel32loadedat76320000
AddressofLoadLibrary=7634361F
MSVCR90.dllloadedat6A340000
Addressofsystemfunction=6A36C88B
Addressoffunctionfoo=00401800
我们看到,即使程序本身没有使用ASLR,Kernel32.dll和MSVCR90.dll的加载地址也发生了变化。这是因为这两个库都已经选择了被ASLR保护。但是应用程序自身foo()函数的地址是固定的。
如果程序使用ASLR功能的话,在WindowsVista下运行。输出的结果是:
Kernel32loadedat763F0000
AddressofLoadLibrary=7641361F
MSVCR90.dllloadedat671F0000
Addressofsystemfunction=6721C88B
Addressoffunctionfoo=003B1800
重启系统
Kernel32loadedat76320000
AddressofLoadLibrary=7634361F
MSVCR90.dllloadedat697A0000
Addressofsystemfunction=697CC88B
Addressoffunctionfoo=00871800
应用程序自身函数foo()的加载地址也随着系统重启发生了变化。即一旦使用了/dynamicbase选项,生成的程序在运行时候就会受到ASLR机制的保护。
4.ASLR的局限
首先,ASLR安全特性只在WindowsVista和其后的Windows版本(如WindowsServer2008)中实现。
5.总结
ASLR安全特性在WindowsVista和其后的Windows版本(如WindowsServer2008)中实现。它可以防范基于Ret2libc方式的针对DEP的攻击。ASLR和DEP配合使用,能有效阻止攻击者在堆栈上运行恶意代码。建议开发人员使用/dynamicbase链接选项让开发的应用程序或动态链接库使用ASLR功能。
6.参考文献
【1】Bypassingnon-executable-stackduringexploitationusingreturn-to-libc,http://www.infosecwriters.com/text_resources/pdf/return-to-libc.pdf,c0ntex
【2】ABriefHistoryofExploitationTechniques&MitigationsonWindows,http://hick.org/~mmiller/presentations/misc/exploitation_techniques_and_mitigations_on_windows.pdf,MattMiller
【3】WritingSecureCodeforWindowsVista,MichaelHoward,DavidLeBlanc
【4】UseofASLR,NX,etc,http://blogs.msdn.com/david_leblanc/archive/2008/03/14/use-of-aslr-nx-etc.aspx,DavidLeBlanc
from:http://blog.csdn.net/chengyun_chu/archive/2009/10/09/4644227.aspx
在前面安全编码实践中我们介绍过GS编译选项和缓存溢出,以及数据保护DEP。首先,缓存溢出的直接后果就是可能导致恶意代码的远程执行,于是编译器提供了GS保护。但是,GS选项有自身的局限,存在若干方法可以绕过GS选项的保护。于是进一步,操作系统提供了数据执行保护,即DEP,以及与之对应的NXCOMPAT编译选项。
那么是不是现在我们就可以高枕无忧了?在安全领域中,系统的攻防是一个不断发展进化的过程。DEP提出后,就出现了针对DEP的Ret2libc攻击手段。这一点我们曾在介绍DEP的安全编码实践文章的最后简单提及过。
ASLR(AddressSpaceLayoutRandomization),地址空间格局的随机化,就是用来防范Ret2libc攻击手段的另一个重要的安全特性。那么,什么是Ret2libc攻击,ASLR的原理是什么,开发人员如何使用这个安全特性,就是我们这篇文章要探讨的内容。
2.DEP和Ret2libc攻击
2.1DEP对堆栈溢出的保护
在栈溢出介绍中提及到Windows体系结构下函数堆栈布局(地址从高向低)如下:
调用参数 |
返回地址 |
EBP上层函数堆栈基址 |
异常处理代码入口地址 (如果函数设置异常处理) |
局部变量 |
如果发生堆栈溢出,恶意代码通过覆盖在堆栈(stack)上的局部变量,从而修改函数的返回地址,而导致恶意代码执行。下面是这类攻击方式的堆栈结构的一个典型例子。
调用参数 | 覆盖方向—> | 恶意代码 |
返回地址 | 恶意代码的入口地址 | |
EBP上层函数堆栈基址 | 溢出的变量覆盖区域,往往包括必要的填充字节 | |
异常处理代码入口地址 (如果函数设置异常处理) | ||
局部变量 |
当DEP保护机制被使用后,由于恶意代码是存放在系统的数据页面(堆栈页面上),那么函数返回时,指令寄存器EIP将跳转到恶意代码的入口地址。此时该页面是非可执行的(non-executable),于是DEP就会触发系统异常而导致程序中止。
2.2Ret2libc攻击
在上述的DEP保护机制中,可以看到关键是在函数返回时EIP跳转到了非可执行页面时被DEP检测到。那么Ret2libc的攻击原理是,攻击者设定的函数的返回地址并不直接指向恶意代码,而是指向一个已存在的系统函数的入口地址。由于系统函数所在的页面权限是可执行的,这样就不会触发DEP异常。
那么,攻击者应该将EIP控制指向那个特殊的系统入口函数?一个例子是在Unix系统下,libc是一个共享的C动态执行库,里面有许多非常有用的函数,例如system函数。它的定义如下:
intsystem(constchar*string);
函数system()可通过运行环境来执行其它程序,例如启动Shell等等。那么,攻击者就可以通过构造以下的堆栈结构【1】:
调用参数 | 覆盖方向—> | /bin/sh |
虚假的返回地址 | ||
返回地址 | system函数的入口地址 | |
EBP上层函数堆栈基址 | 溢出的变量覆盖区域,往往包括必要的填充字节 | |
异常处理代码入口地址 (如果函数设置异常处理) | ||
局部变量 |
这样,当发生堆栈溢出的函数返回时,EIP跳转到system函数。因为system函数本身就是可执行的,这时不会产生DEP异常。攻击者通过构造system函数的调用参数来可以启动其它程序。在攻击过程中,函数返回到libc库(returntolibc)是关键,这也就是Ret2libc名字的来由。
细心的读者也许已经发现,在表3中,没有任何恶意代码被插入。攻击者虽然可以通过system或者其它系统函数来执行很多敏感的操作,但在多数情况下,还是更希望可以执行自身定制的恶意代码。如何可以做到这一点?于是在最初的Ret2libc的攻击方式的基础上,又发展出特别针对Windows系统攻击的手段。它的原理是通过VirtualProtect函数来修改恶意代码所在内存页面的执行权限,然后再将控制转移到恶意代码。
VirtualProtect是Windows系统kernel32.dll提供的函数,其功能是修改调用进程所在虚拟地址空间(virtualaddress)的内存区域的保护权限。它的定义如下:
BOOLWINAPIVirtualProtect(
__inLPVOIDlpAddress,
__inSIZE_TdwSize,
__inDWORDflNewProtect,
__outPDWORDlpflOldProtect
);
攻击者构造以下的堆栈结构【2】来调用VirtualProtect:
调用参数 | 覆盖方向—> | 恶意代码 |
lpflOldProtect值 | ||
设定可执行权限参数 | ||
恶意代码页面的大小 | ||
恶意代码所在内存页面的基址 | ||
恶意代码的入口地址 | ||
返回地址 | VirtualProtect函数的入口地址 | |
EBP上层函数堆栈基址 | 溢出的变量覆盖区域,往往包括必要的填充字节 | |
异常处理代码入口地址 (如果函数设置异常处理) | ||
局部变量 |
首先,当发生堆栈溢出的函数返回时,EIP跳转到VirtualProtect函数。注意到这里攻击者特别构造将恶意代码的入口地址作为VirtualProtect函数退出时的返回地址。由于在VirtualProtect的执行过程中,恶意代码所在的页面被修改为可执行权限,这样当VirtualProtect返回时,EIP再跳转到恶意代码时就不会触发任何DEP异常。
除了使用VirtualProtect函数,攻击者还可以使用其它函数,例如NtSetInformationProcess等等。
3.ASLR和/dynamicbase链接选项
在上面对Ret2libc攻击方式的介绍中,我们看到最为关键的一点是攻击者事先预知了特定函数,如system或VirtualProtect的入口地址。在WindowsXP或Windows2000上,这些函数的入口地址是固定的,即攻击者事先可以确定的。
在WindowsVista中引入了ASLR安全特性。它的原理就是在当一个应用程序或动态链接库,如kernel32.dll,被加载时,如果其选择了被ASLR保护,那么系统就会将其加载的基址随机设定。这样,攻击者就无法事先预知动态库,如kernel32.dll的基址,也就无法事先确定特定函数,如VirtualProtect,的入口地址了。
ASLR是系统一级的特性。系统动态库,如kernel32.dll,加载地址,是在系统每次启动的时候被随机设定的。
下面是一个简化的ASLR演示程序【3】。
//aslr.cpp:DemothedynamicbaseofDLLsduetoASLR
//
#include"stdafx.h"
#include<windows.h>
#include<stdio.h>
voidfoo(void)
{
printf("Addressoffunctionfoo=%p/n",foo);
}
int_tmain(intargc,_TCHAR*argv[])
{
HMODULEhMod=LoadLibrary(L"Kernel32.dll");
//Note—thisisforreleasebuilds
HMODULEhModMsVc=LoadLibrary(L"MSVCR90.dll");
void*pvAddress=GetProcAddress(hMod,"LoadLibraryW");
printf("Kernel32loadedat%p/n",hMod);
printf("AddressofLoadLibrary=%p/n",pvAddress);
pvAddress=GetProcAddress(hModMsVc,"system");
printf("MSVCR90.dllloadedat%p/n",hModMsVc);
printf("Addressofsystemfunction=%p/n",pvAddress);
foo();
if(hMod)FreeLibrary(hMod);
if(hModMsVc)FreeLibrary(hModMsVc);
return0;
}
这段程序的目的是输出kerner32.dll和msvcr90.dll的基址,loadlibrary和system函数的入口地址,以及应用程序本身一个函数foo()的入口地址。
使用ASLR非常简单。从VisualStudio2005SP1开始,增加了/dynamicbase链接选项。/dynamicbase选项可以通过ProjectProperty->ConfigurationProperties->Linker->Advanced->RandomizedBaseAddress,或直接修改linker的命令行编译选项即可。
在VisualStudio2008环境,用Win32ConsoleApplication类型,编译链接演示程序。注意,如果使用VisualStudio2005SP1的话,需要将msvcr90.dll更改为msvcr80.dll。
如果程序没有使用ASLR功能的话,在WindowsVista下运行。输出的结果是:
Kernel32loadedat763F0000
AddressofLoadLibrary=7641361F
MSVCR90.dllloadedat671F0000
Addressofsystemfunction=6721C88B
Addressoffunctionfoo=00401800
重启系统
Kernel32loadedat76320000
AddressofLoadLibrary=7634361F
MSVCR90.dllloadedat6A340000
Addressofsystemfunction=6A36C88B
Addressoffunctionfoo=00401800
我们看到,即使程序本身没有使用ASLR,Kernel32.dll和MSVCR90.dll的加载地址也发生了变化。这是因为这两个库都已经选择了被ASLR保护。但是应用程序自身foo()函数的地址是固定的。
如果程序使用ASLR功能的话,在WindowsVista下运行。输出的结果是:
Kernel32loadedat763F0000
AddressofLoadLibrary=7641361F
MSVCR90.dllloadedat671F0000
Addressofsystemfunction=6721C88B
Addressoffunctionfoo=003B1800
重启系统
Kernel32loadedat76320000
AddressofLoadLibrary=7634361F
MSVCR90.dllloadedat697A0000
Addressofsystemfunction=697CC88B
Addressoffunctionfoo=00871800
应用程序自身函数foo()的加载地址也随着系统重启发生了变化。即一旦使用了/dynamicbase选项,生成的程序在运行时候就会受到ASLR机制的保护。
4.ASLR的局限
首先,ASLR安全特性只在WindowsVista和其后的Windows版本(如WindowsServer2008)中实现。
其次,ASLR是需要和DEP配合使用的。如果CPU不提供对于DEP的硬件支持,或者应用程序没有选择被DEP保护的话,恶意代码一旦可以执行,就可以通过程序进程表结构来获得特定DLL的加载基址。
就性能和兼容性
而言,ASLR的实现上都做了考虑,没有太多的影响。一个范例是MicrosoftOffice2007。Office2007的程序全面使用ASLR功能,并没有发现对其
性能和兼容性带来太大的影响【4】
。
5.总结
ASLR安全特性在WindowsVista和其后的Windows版本(如WindowsServer2008)中实现。它可以防范基于Ret2libc方式的针对DEP的攻击。ASLR和DEP配合使用,能有效阻止攻击者在堆栈上运行恶意代码。建议开发人员使用/dynamicbase链接选项让开发的应用程序或动态链接库使用ASLR功能。
6.参考文献
【1】Bypassingnon-executable-stackduringexploitationusingreturn-to-libc,
【2】ABriefHistoryofExploitationTechniques&MitigationsonWindows,
【3】WritingSecureCodeforWindowsVista,MichaelHoward,DavidLeBlanc
【4】UseofASLR,NX,etc,
from:
相关文章推荐
- 空间格局随机化ASLR
- 空间格局随机化ASLR
- 安全编码实践之五地址空间格局随机化ASLR
- 安全编码实践之五地址空间格局随机化ASLR
- 安全编码实践之五地址空间格局随机化ASLR
- Ubuntu关闭地址空间随机化(ASLR)的方法
- ASLR(Address space layout randomization)地址空间布局随机化
- 对抗栈帧地址随机化/ASLR的两种思路和一些技巧
- linux关闭地址空间随机化(ASLR)
- 空间数据库的开源格局
- ASLR(Address space layout randomization)地址空间布局随机化
- Ziddu - 能帮你赚美元的无限空间免费网络硬盘
- 主机屋免费空间延期
- varchar(n),nvarchar(n) 长度、性能、及所占空间分析
- Hololens入门之空间映射
- Oracle临时表空间不够,导致查询出错。
- Ubuntu : 如何显示当前系统的空间使用h
- oracle 11g 传输表空间(数据迁移)
- ArcEngine 创建空间参考设置默认域
- 给线程变量pthread_t *thread动态分配空间