2014年,OpenSSL加密库中的一个缓冲区溢出漏洞被公开。该缺陷被称为“心脏出血”。它使受欢迎的在线服务和软件平台的数亿用户暴露于易受攻击的OpenSSL软件版本中。于是操作系统提供了许多安全机制来尝试降低或阻止缓冲区溢出攻击带来的安全风险,包括DEPLinux下对应NX)、ASLRLinux下对应PIE)等。我们先从什么是缓冲区溢出开始。

什么是缓冲区溢出?

缓冲区溢出漏洞,顾名思义,就是计算机对接收的输入数据没有进行有效的检测(理想的情况是程序检查数据长度并不允许输入超过缓冲区长度的字符),向缓冲区内填充数据时超过了缓冲区本身的容量,而导致数据溢出到被分配空间之外的内存空间,使得溢出的数据覆盖了其他内存空间的数据。

缓冲区溢出代码示例

缓冲区溢出的想法很简单。以下是具有缓冲区溢出漏洞的C程序的源代码:

char greeting[5];
memcpy(greeting, "Hello, world!\n", 15);
printf(greeting);

当我们编译并运行此有漏洞的程序时,你认为会发生什么?答案可能令人惊讶:任何事情都可能发生。执行此代码段时,它将尝试将15个字节放入只有5个字节长的目标缓冲区中。这意味着将有十个字节写入数组外部的内存地址。以后发生的情况取决于被覆盖的十个字节的内存的原始内容。也许重要的变量存储在这里,而我们刚好更改了它们的值?

如何防止缓冲区溢出

通常的做法是编写安全的代码。同时当今的操作系统以不可执行的堆栈和地址空间布局随机化(ASLR)的形式提供了其他防御措施。不可执行的堆栈(即数据执行保护DEP)将堆栈以及在某些情况下的其他结构标记为无法执行代码的区域。这意味着攻击者无法将利用代码注入堆栈并期望其成功运行。

编写安全的代码

编写正确的代码是一件非常有意义的工作,特别像编写C语言那种风格自由而容易出错的程序,这种风格是由于追求性能而忽视正确性的传统引起的。尽管花了很长的时间使得人们知道了如何编写安全的程序,具有安全漏洞的程序依旧出现。比如C标准库里面的strcpystrcatsprintf函数都没有缓冲区溢出保护功能。
程序员必须通过始终验证用户输入长度来避免缓冲区溢出攻击。但是,避免缓冲区溢出漏洞的一种通用方法是坚持使用包括缓冲区溢出保护的安全功能。此类功能可在不同平台上使用,例如,strlcpystrlcatsnprintfOpenBSD)或strcpy_sstrcat_ssprintf_sWindows)。下表列出了有C标准库漏洞函数的一些更安全替代品:
在这里插入图片描述

Linux系统中的DEPASLR保护机制

Linux系统中的DEP通过NX来实现,NXNo-eXecute(不可执行)的意思,NX的基本原理是将数据所在内存页标识为不可执行,当程序溢出成功转入shellcode时,程序会尝试在数据页面上执行指令,此时CPU就会抛出异常,而不是去执行恶意指令。
gcc编译器默认开启了NX选项,如果需要关闭NX选项,可以给gcc编译器添加-z execstack参数。
例如:

gcc -o test test.c					// 默认情况下,开启NX保护
gcc -z execstack -o test test.c		// 禁用NX保护
gcc -z noexecstack -o test test.c	// 开启NX保护

开发ASLR是为了防御面向返回的程序设计(一种针对非可执行堆栈的解决方法,在该堆栈中,现有代码段根据其在内存中的地址偏移量被链接在一起),ASLRDEP配合使用,能有效阻止攻击者在堆栈上运行恶意代码。内存地址随机化机制有以下三种情况:

0 - 表示关闭进程地址空间随机化。
1 - 表示将mmap的基址,stack和vdso页面随机化。
2 - 表示在1的基础上增加堆(heap)的随机化。

Linux系统中的ASLR机制是通过PIE(position-independent executables)来实现的。gcc编译命令如下:

# -fPIE/-fpie这个选项与-fPIC/-fpic大致相同,不同点在于:-fPIC用于生成动态库,-fPIE用与生成可执行文件。
gcc -o test test.c				// 默认情况下,不开启PIE
gcc -fpie -pie -o test test.c		// 开启PIE,此时强度为1
gcc -fPIE -pie -o test test.c		// 开启PIE,此时为最高强度2
gcc -fpic -o test test.c		// 开启PIC,此时强度为1,不会开启PIE
gcc -fPIC -o test test.c		// 开启PIC,此时为最高强度2,不会开启PIE
使用checksec工具来检查系统和程序的属性

Checksec是一个bash脚本,用于检查可执行文件的属性(例如PIE,RELRO,PaX,Canaries,ASLR,Fortify Source)。源码请参考:checksec.sh
首先我们下载这个工具:

$ git clone https://github.com/slimm609/checksec.sh.git

然后我们就可以使用这个工具来检查Linux系统和程序的一些安全属性,包括之前提到的DEPASLR机制,下面是一些简单的例子:

$ cd checksec.sh
$ ./checksec --file=/bin/ls  
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      Symbols         FORTIFY Fortified       Fortifiable     FILE
Full RELRO      Canary found      NX enabled    PIE enabled     No RPATH   No RUNPATH   No Symbols        Yes   5               17              /bin/ls

$ ./checksec --kernel      
* Kernel protection information:

  Description - List the status of kernel protection mechanisms. Rather than
  inspect kernel mechanisms that may aid in the prevention of exploitation of
  userspace processes, this option lists the status of kernel configuration
  options that harden the kernel itself against attack.

  Kernel config:
    /boot/config-5.3.0-45-generic

  Warning: The config on disk may not represent running kernel config!
           Running kernel: 5.3.0-45-generic

  Vanilla Kernel ASLR:                    Full
  NX protection:                          Skipped
  Protected symlinks:                     sysctl: permission denied on key 'fs.protected_symlinks'
Disabled
  Protected hardlinks:                    sysctl: permission denied on key 'fs.protected_hardlinks'
Disabled
  Protected fifos:                        sysctl: permission denied on key 'fs.protected_fifos'
Unsupported
  Protected regular:                      sysctl: permission denied on key 'fs.protected_regular'
Unsupported
  Ipv4 reverse path filtering:            Enabled
  Kernel heap randomization:              Enabled
  GCC stack protector support:            Enabled
  GCC stack protector strong:             Enabled
  SLAB freelist randomization:            Enabled
  Virtually-mapped kernel stack:          Enabled
  Restrict /dev/mem access:               Enabled
  Restrict I/O access to /dev/mem:        Disabled
  Enforce read-only kernel data:          Enabled
  Enforce read-only module data:          Enabled
  Full reference count validation:        Disabled
  Exec Shield:                            Unsupported

  Hardened Usercopy:                      Enabled
  Harden str/mem functions:               Enabled
  Restrict /dev/kmem access:              Enabled

* X86 only:            
  Address space layout randomization:     Enabled

* SELinux:                                Disabled

  SELinux infomation available here: 
    http://selinuxproject.org/

* grsecurity / PaX:                       No GRKERNSEC

  The grsecurity / PaX patchset is available here:
    http://grsecurity.net/

而这个强大的工具同样可以在嵌入式Linux系统中直接使用,这简直是太棒了!

Logo

更多推荐