应用程序的安全

文章结构

 

0.什么是“应用程序的安全”?

许多攻击并不直接利用操作系统内核的弱点,而是攻击不安全的程序

这些程序甚至是非内核的操作系统程序 (如更改密码程序),它的运行权限要高于普通用户的权限。因此,要保护这些应用程序免受特权提升的攻击。

 

1. 编译与链接

编译:将源程序转换成处理器能执行的机器代码指令的过程。

使用静态链接动态链接都能对程序进行编译。

静态链接:程序执行期间所需的所有共享库都要复制到磁盘上的编译程序中。从安全角度而言,这样做会更加安全,但因为重复代码会占用额外的空间,许多程序还要使用这些空间,所以会很不方便,另外,这还可能限制调试选项。

态链接:当程序真正运行时,才会加载共享库。

       既节省硬盘空间,又允许开发者将代码模块化。

当执行程序时,加载程序确定需要哪些共享库,然后在磁盘上找到这些库,并将它们导入进程的地址空间。也就是说,不需要重新编译整个应用程序。

例:DLL注入。为了修复DLL产生的漏洞,可能只需要改变一个DLL,但可能会影响许多其他程序。通过共享库向程序注入任意代码的过程称为DLL注入。对于调试,DLL注入非常有用,程序员无需重新编译代码就能轻松地改变应用程序的功能。但是这种技术也构成了潜在的安全风险,因为通过这种技术,恶意方能向合法程序注入自己的代码

 

2.简单的缓冲区溢出攻击

攻击者提供的输入可能会超过缓冲区的大小,而程序仍会尽职尽责地向缓冲区复制所分配地输入。这种复制可能会覆盖内存缓存区位置外的数据,从而使攻击者获得整个进程的控制权,并在计算机上执行任意代码。

允许特权提升、针对应用程序攻击的一个典型示例就是缓冲区溢出攻击

在任何情况下,都会在内存中为程序分配固定大小的缓冲区,用于存储信息,必须注意,要确保安全地向缓冲区复制用户提供地数据,并进行边界检查。

例:最简单的溢出条件使对整数在内存中表示的溢出——算术溢出

32位整数:0x00000001~0x7fffffff为正数(1~2147483647)

                  0x80000000 ~0xffffffff为负数(-2147483648~-1)

0x7fffffff + 1 = -2147483648        0x80000000-1 =  2147483647  

攻击者通过发送大量的连接请求,使连接计数器溢出,计数值变为零或负数,攻击者就可以危害上述系统。

为了防止这种类型的攻击,必须使用安全的编程实践,以确保整数不会无限制地递增或递减。

    

 

3. 基于堆栈的缓冲区溢出

       堆栈是进程内存地址空间的的组成部分,它包含与函数调用相关联的数据。堆栈由帧组成,每个帧都与激活的调用相关联。帧存储着局部变量、调用参数和父进程调用的返回地址。

       在缓冲区溢出攻击中,程序将攻击者提供的输入盲目地复制到比输入小地缓冲区。通常是使用了不检查地C库函数strcpy()gets()

argv[1],这个字符串不论多长,执行的时候,都会把它复制到buf这个内存中,越界之后就会把后面的内容给破坏掉,如果argv是设计好的恶意代码,可能就会产生严重后果。

 在基于堆栈的缓冲区溢出攻击中,攻击者可以覆盖与局部变量内存相邻的缓冲区,会产生意外的操作。

在堆栈溢出攻击中,攻击者利用堆栈缓冲区的脆弱性,在堆栈中注入恶意代码,并覆盖当前例程返回的地址,以便当前例程终止时,将执行权限传递给攻击者的恶意代码,而不是传递给调用例程。因此,出现这种上下文切换时,代表攻击者的进程将执行恶意代码。

堆栈溢出攻击,假设攻击者知道返回地址的位置。

a)在攻击前,返回地址指向程序代码的位置。

b)利用未受保护的缓冲区,攻击者注入地址空间输入,该输入包括填充的返回地址位置、指向下一个内存位置的修改后的返回地址和恶意代码。在当前例程执行完成后,控制传递给恶意代码。

攻击者面临的问题:猜测缓冲区中返回地址的位置,并确定用什么地址覆盖返回地址,以便攻击者的代码得以执行。

操作系统设计的本质形成了这种挑战。究其原因共有两个:

       其一,进程不能访问其他进程的地址空间,因此恶意代码必须驻留在被利用进程的地址空间内。正因为如此,恶意代码通常将自身保存在缓冲区之中,当进程启动时,将自己作为参数传递给进程,或者保存在用户的外壳环境中,然后再导入进程的地址空间。

       其二,给定进程的地址空间是不可预测的,当程序在不同计算机上运行时,地址空间可能会发生变化。

所以,要确切知道在堆栈中缓冲区的主流位置也是非常困难的,必须进行猜测。

攻击者为了克服这些挑战,已开发了若干项技术。下面就介绍三种常见的方法。

1NOP指令滑动

NOP的核心思想就是

通过递增目标的大小,攻击者能成功地猜测出代码在内存中地位置。

利用这项技术,攻击者制造有效负载,该负载包含使缓冲区溢出的适量数据、猜测出地进程地址空间中合理地返回地址、大量NOP指令和恶意代码。

当为脆弱的程序提供该有效负载时,程序将有效负载复制到内存,覆盖攻击者猜测的返回地址。在成功的攻击中,进程会跳转到猜测的返回地址,这会需要大量的NOP指令,然后,处理器划过所有NOP指令,直到最后到达恶意代码,并执行恶意代码。

外壳代码:在漏洞中包括的恶意代码称为外壳代码(shellcode)。

尽管NOP指令滑动使基于堆栈的缓冲区溢出攻击更容易成功,但仍需要大量的猜测,而猜测并不十分可靠。另一种称为跳转到寄存器跳转的技术更为精确。

2)跳转

在初始化时,大多数进程将外部库的内容加载到自己的地址空间内。因为是将这些外部库加载到内存预留段的进程地址空间之中,所以可以预测外部库的内存位置。攻击者可以利用这些外部库的知识,执行跳转攻击

:攻击者直到Windows核心系统DLL中特定的程序集代码指令,假设该指令告诉处理器跳转到某一地址,该地址存储在处理器的某一寄存器中,如果攻击者可以设法把寄存器指向恶意代码的地址,覆盖已知指令地址的当前函数的返回地址,然后再返回,应用程序将跳转,并执行jmp esp指令,结果是执行攻击者的恶意代码。

3return-to-libc攻击

Return-to-libc攻击也利用了运行时外部库的加载,是使用C库的函数,即libc的函数。

如果攻击者能在脆弱进程的地址空间内确定C库函数的地址,如system()execv()的位置,将使用这些信息强制程序调用函数。攻击者可以使缓冲区溢出,用所需库函数的地址覆盖返回地址libc函数完成执行时,攻击者必须提供一个新地址,libc函数将返回这个新地址,按地址指向该函数的任何参数。

当脆弱的堆栈帧返回时,它讲调用所选择的函数,该函数使用所提供的参数,攻击者就能达到完全控制系统。这项技术的优势在于:在堆栈不执行任何代码。堆栈只包含已有函数的参数,而不是实际的外壳代码。因此,甚至堆栈被标记为不可执行时,也能实施这种攻击。

防止基于堆栈的缓冲区溢出攻击

1)缓冲区溢出的根源不在于操作系统本身,而在于不安全的编程实践

    如:用strncpy()代替strcpy().

2)许多OS都采用了保护机制,用于检测是否发生了基于堆栈的而缓冲区溢出。若溢出,就控制恶意代码的重定向。

    如:在缓冲区和控制数据之间设置一个cannary值,定期检查cannary值的完整性,如果值被修改,则表明已溢出,就防止恶意代码的执行。

3Point-Guard:增加了指针的XOR编码,在指针使用前后都包含返回地址。

4)通过在内存的堆栈段设置非执行权限,以防止在堆栈上运行代码。

5)地址空间布局随机化,它随机地重新安排进程地址空间的数据,使攻击者很难预测:为了执行代码,需要跳转到哪个位置。

 

4. 基于堆的缓冲区溢出攻击

从安全角度来看,堆存在的问题与堆栈类似。

基于堆的溢出通常比流行的基于堆栈的缓冲区溢出更复杂。

与堆栈不同,如果改变了程序的执行,堆会包含控制数据,堆本质上是用于数据的大量空闲空间。堆溢出不是直接修改控制,而是修改堆中的数据或者滥用函数及管理堆内存的宏,从而执行任意代码。

防止基于堆的缓冲区溢出攻击

1地址空间的随机化 能防止攻击者可靠地猜测内存地位置。

2)一些系统使堆不可执行(代码)

3安全编程——最重要地预防措施。

 

6. 竞争条件

竞争条件是指在任何情况下程序的行为都是无意的,只取决于特定事件的分时。

一个典型的实例就是C函数的access()open()的使用。

在对access()open()的调用之间有微小的、几乎不可察觉的时间延迟。攻击者可以利用这两个调用间的微小延迟来改变有问题的文件。

举例来说,嘉定攻击者提供A文件作为参数,它是允许访问的。但在调用access()之后,攻击者快速用其他没有权限读取的文件的符号链接替换A文件的。这样,程序会调用open()打开符号链接的文件。

不过这个替换操作肯定不是人手动来实现的。

一般来说,这种类型的脆弱性也称为检查时间/使用时间的问题

这个问题的解决方案呢,也不难,主要还是要求程序员进行安全编程。

这个例子中,就尽量避免使用access(),程序在调用access()之前,使用seteuid()去掉它的特权。这样,如果用户运行的程序没有权限打开制定的文件,则调用open()会失败。

getuid :返回一个调用程序的真实用户ID。当前运行位置程序的执行者。

geteuid :返回一个有效用户的ID。euid是最初执行程序时所有的ID。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

牧心.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值