安全编码实践之五地址空间格局随机化ASLR

来源:互联网 发布:2017淘宝商家数量统计 编辑:程序博客网 时间:2024/05/13 03:33

1.     概述: http://blog.csdn.net/chengyun_chu/article/details/4644227

在前面安全编码实践中我们介绍过GS编译选项和缓存溢出,以及数据保护DEP。首先,缓存溢出的直接后果就是可能导致恶意代码的远程执行,于是编译器提供了GS保护。但是,GS选项有自身的局限,存在若干方法可以绕过GS选项的保护。于是进一步,操作系统提供了数据执行保护,即DEP,以及与之对应的NXCOMPAT编译选项。

那么是不是现在我们就可以高枕无忧了?在安全领域中,系统的攻防是一个不断发展进化的过程。DEP提出后,就出现了针对DEP的Ret2libc攻击手段。这一点我们曾在介绍DEP的安全编码实践文章的最后简单提及过。

ASLR(Address Space Layout Randomization),地址空间格局的随机化,就是用来防范Ret2libc攻击手段的另一个重要的安全特性。那么,什么是Ret2libc攻击,ASLR的原理是什么,开发人员如何使用这个安全特性,就是我们这篇文章要探讨的内容。

2.     DEP和Ret2libc攻击

2.1 DEP对堆栈溢出的保护

在栈溢出介绍中提及到Windows体系结构下函数堆栈布局(地址从高向低)如下:

调用参数

返回地址

EBP上层函数堆栈基址

异常处理代码入口地址

(如果函数设置异常处理)

局部变量

表1:Windows系统的函数堆栈结构

 

如果发生堆栈溢出,恶意代码通过覆盖在堆栈(stack)上的局部变量,从而修改函数的返回地址,而导致恶意代码执行。下面是这类攻击方式的堆栈结构的一个典型例子。

调用参数

覆盖方向—>

恶意代码

返回地址

恶意代码的入口地址

EBP上层函数堆栈基址

溢出的变量覆盖区域,往往包括必要的填充字节

异常处理代码入口地址

(如果函数设置异常处理)

局部变量

表2:堆栈溢出时的堆栈结构

当DEP保护机制被使用后,由于恶意代码是存放在系统的数据页面(堆栈页面上),那么函数返回时,指令寄存器EIP将跳转到恶意代码的入口地址。此时该页面是非可执行的(non-executable),于是DEP就会触发系统异常而导致程序中止。

2.2 Ret2libc攻击

 

在上述的DEP保护机制中,可以看到关键是在函数返回时EIP跳转到了非可执行页面时被DEP检测到。那么Ret2libc的攻击原理是,攻击者设定的函数的返回地址并不直接指向恶意代码,而是指向一个已存在的系统函数的入口地址。由于系统函数所在的页面权限是可执行的,这样就不会触发DEP异常。

 

那么,攻击者应该将EIP控制指向那个特殊的系统入口函数?一个例子是在Unix 系统下,libc是一个共享的C动态执行库,里面有许多非常有用的函数,例如system函数。它的定义如下:

int system(const char *string);

 

函数system()可通过运行环境来执行其它程序,例如启动Shell等等。那么,攻击者就可以通过构造以下的堆栈结构【1】:

 

调用参数

覆盖方向—>

/bin/sh

虚假的返回地址

返回地址

system函数的入口地址

EBP上层函数堆栈基址

溢出的变量覆盖区域,往往包括必要的填充字节

异常处理代码入口地址

(如果函数设置异常处理)

局部变量

表3:Ret2libc攻击的堆栈结构

 

这样,当发生堆栈溢出的函数返回时,EIP跳转到system函数。因为system函数本身就是可执行的,这时不会产生DEP异常。攻击者通过构造system函数的调用参数来可以启动其它程序。在攻击过程中,函数返回到libc库(return to libc)是关键,这也就是Ret2libc名字的来由。

细心的读者也许已经发现,在表3中,没有任何恶意代码被插入。攻击者虽然可以通过system或者其它系统函数来执行很多敏感的操作,但在多数情况下,还是更希望可以执行自身定制的恶意代码。如何可以做到这一点?于是在最初的Ret2libc的攻击方式的基础上,又发展出特别针对Windows系统攻击的手段。它的原理是通过VirtualProtect函数来修改恶意代码所在内存页面的执行权限,然后再将控制转移到恶意代码。

VirtualProtect是Windows系统kernel32.dll提供的函数,其功能是修改调用进程所在虚拟地址空间(virtual  address)的内存区域的保护权限。它的定义如下:

 

BOOL WINAPI VirtualProtect(

  __in   LPVOID lpAddress,

  __in   SIZE_T dwSize,

  __in   DWORD flNewProtect,

  __out  PDWORD lpflOldProtect

);

 

攻击者构造以下的堆栈结构【2】来调用VirtualProtect:

 

 

调用参数

覆盖方向—>

恶意代码

lpflOldProtect值

设定可执行权限参数

恶意代码页面的大小

恶意代码所在内存页面的基址

恶意代码的入口地址

返回地址

VirtualProtect函数的入口地址

EBP上层函数堆栈基址

溢出的变量覆盖区域,往往包括必要的填充字节

异常处理代码入口地址

(如果函数设置异常处理)

局部变量

表4:使用VirtualProtect攻击的堆栈结构

 

首先,当发生堆栈溢出的函数返回时,EIP跳转到VirtualProtect函数。注意到这里攻击者特别构造将恶意代码的入口地址作为VirtualProtect函数退出时的返回地址。由于在VirtualProtect的执行过程中,恶意代码所在的页面被修改为可执行权限,这样当VirtualProtect返回时,EIP再跳转到恶意代码时就不会触发任何DEP异常。

除了使用VirtualProtect函数,攻击者还可以使用其它函数,例如NtSetInformationProcess等等。

3.     ASLR和/dynamicbase链接选项

在上面对Ret2libc攻击方式的介绍中,我们看到最为关键的一点是攻击者事先预知了特定函数,如system或VirtualProtect的入口地址。在Windows XP或Windows 2000上,这些函数的入口地址是固定的,即攻击者事先可以确定的。

 

在Windows Vista中引入了ASLR安全特性。它的原理就是在当一个应用程序或动态链接库,如kernel32.dll,被加载时,如果其选择了被ASLR保护,那么系统就会将其加载的基址随机设定。这样,攻击者就无法事先预知动态库,如kernel32.dll的基址,也就无法事先确定特定函数,如VirtualProtect,的入口地址了。

ASLR是系统一级的特性。系统动态库,如kernel32.dll,加载地址,是在系统每次启动的时候被随机设定的。

 

下面是一个简化的ASLR演示程序【3】。

 

// aslr.cpp : Demo the dynamic base of DLLs due to ASLR

//

 

#include "stdafx.h"

#include <windows.h>

#include <stdio.h>

 

void foo( void )

{

      printf( "Address of function foo = %p/n", foo );

}

 

int _tmain(int argc, _TCHAR* argv[])

{

      HMODULE hMod = LoadLibrary( L"Kernel32.dll" );

      // Note—this is for release builds

      HMODULE hModMsVc = LoadLibrary( L"MSVCR90.dll" );

 

      void* pvAddress = GetProcAddress(hMod, "LoadLibraryW");

      printf( "Kernel32 loaded at %p/n", hMod );

      printf( "Address of LoadLibrary = %p/n", pvAddress );

      pvAddress = GetProcAddress( hModMsVc, "system" );

      printf( "MSVCR90.dll loaded at %p/n", hModMsVc );

      printf( "Address of system function = %p/n", pvAddress );

 

      foo();

 

      if( hMod ) FreeLibrary( hMod );

      if( hModMsVc ) FreeLibrary( hModMsVc );

      return 0;

}

 

这段程序的目的是输出kerner32.dll和msvcr90.dll的基址,loadlibrary和system函数的入口地址,以及应用程序本身一个函数foo()的入口地址。

使用ASLR非常简单。从Visual Studio 2005 SP1开始,增加了/dynamicbase链接选项。/dynamicbase选项可以通过Project Property -> Configuration Properties -> Linker -> Advanced -> Randomized Base Address,或直接修改linker的命令行编译选项即可。见下图。

 

图1:/dynamicbase链接选项配置

在Visual Studio 2008环境,用Win32 Console Application类型,编译链接演示程序。注意,如果使用Visual Studio 2005 SP1的话,需要将msvcr90.dll更改为msvcr80.dll。

如果程序没有使用ASLR功能的话,在Windows Vista下运行。输出的结果是:

Kernel32 loaded at 763F0000

Address of LoadLibrary = 7641361F

MSVCR90.dll loaded at 671F0000

Address of system function = 6721C88B

Address of function foo = 00401800

 

重启系统

 

Kernel32 loaded at 76320000

Address of LoadLibrary = 7634361F

MSVCR90.dll loaded at 6A340000

Address of system function = 6A36C88B

Address of function foo = 00401800

 

我们看到,即使程序本身没有使用ASLR,Kernel32.dll和MSVCR90.dll的加载地址也发生了变化。这是因为这两个库都已经选择了被ASLR保护。但是应用程序自身foo()函数的地址是固定的。

如果程序使用ASLR功能的话,在Windows Vista下运行。输出的结果是:

Kernel32 loaded at 763F0000

Address of LoadLibrary = 7641361F

MSVCR90.dll loaded at 671F0000

Address of system function = 6721C88B

Address of function foo = 003B1800

 

重启系统

 

Kernel32 loaded at 76320000

Address of LoadLibrary = 7634361F

MSVCR90.dll loaded at 697A0000

Address of system function = 697CC88B

Address of function foo = 00871800

 

应用程序自身函数foo()的加载地址也随着系统重启发生了变化。即一旦使用了/dynamicbase选项,生成的程序在运行时候就会受到ASLR机制的保护。

4.     ASLR的局限

首先,ASLR安全特性只在Windows Vista和其后的Windows版本(如Windows Server 2008)中实现。

 

其次,ASLR是需要和DEP配合使用的。如果CPU不提供对于DEP的硬件支持,或者应用程序没有选择被DEP保护的话,恶意代码一旦可以执行,就可以通过程序进程表结构来获得特定DLL的加载基址。

 

就性能和兼容性而言,ASLR的实现上都做了考虑,没有太多的影响。一个范例是Microsoft Office 2007。Office 2007的程序全面使用ASLR功能,并没有发现对其性能和兼容性带来太大的影响【4】

 

5.     总结

ASLR安全特性在Windows Vista和其后的Windows版本(如Windows Server 2008)中实现。它可以防范基于Ret2libc方式的针对DEP的攻击。ASLR和DEP配合使用,能有效阻止攻击者在堆栈上运行恶意代码。建议开发人员使用/dynamicbase链接选项让开发的应用程序或动态链接库使用ASLR功能。

 

6.     参考文献

【1】      Bypassing non-executable-stack during exploitation using return-to-libc,http://www.infosecwriters.com/text_resources/pdf/return-to-libc.pdf,c0ntex

【2】      A Brief History of Exploitation Techniques & Mitigations on Windows,http://hick.org/~mmiller/presentations/misc/exploitation_techniques_and_mitigations_on_windows.pdf Matt Miller

【3】      Writing Secure Code for Windows Vista, Michael Howard, David LeBlanc

【4】      Use of ASLR, NX, etc,http://blogs.msdn.com/david_leblanc/archive/2008/03/14/use-of-aslr-nx-etc.aspx,David LeBlanc

原创粉丝点击