• 我们在哪一颗星上见过 ,以至如此相互思念 ;我们在哪一颗星上相互思念过,以至如此相互深爱
  • 我们在哪一颗星上分别 ,以至如此相互辉映 ;我们在哪一颗星上入睡 ,以至如此唤醒黎明
  • 认识世界 克服困难 洞悉所有 贴近生活 寻找珍爱 感受彼此

漏洞学习:缓冲区溢出

漏洞学习 云涯 2年前 (2021-11-18) 1921次浏览

概念

目前有两种主要类型的缓冲区溢出

  • 基于堆
  • 基于堆栈

堆与堆栈

在程序执行之前,加载程序为其分配一个虚拟地址空间,其中包括堆和堆栈的地址。

  • 堆是一块内存,用于全局变量和变量在运行时分配的内存(动态分配)。
  • 就像自助餐上的一堆盘子一样,软件栈是由保存被调用函数的局部变量的框架构成的。调用函数时将帧压入(放入)堆栈,并在返回时从堆栈中弹出(移出)。如果有多个线程,那么就有多个堆栈。
  • 与堆相比,堆栈非常快。但使用堆栈有两个缺点。首先,堆栈内存是有限的,这意味着将大数据结构放在堆栈上会更快地耗尽可用地址。其次,每个帧的生命周期仅限于它在堆栈中的存在,这意味着从已从堆栈中弹出的帧访问数据是无效的。如果多个函数需要访问相同的数据,最好将数据放在堆上,并将指向该数据的指针(其地址)传递给这些函数。
  • 缓冲区溢出可能发生在堆和堆栈中

基于堆栈的缓冲区溢出:覆盖返回地址

由于每次函数调用时帧都堆叠在彼此的顶部,返回地址也被压入堆栈,告诉程序在调用函数完成时继续执行的位置。

返回地址位于保存局部变量的缓冲区附近。因此,如果一个恶意程序成功地将更多的数据写入缓冲区,超过了它所能容纳的,那么就会发生缓冲区溢出。不适合预期缓冲区的数据可能会溢出到返回地址并覆盖它。

如果在易受攻击的程序的典型使用中发生缓冲区溢出,通常情况下,被覆盖的返回地址的新值不是有效的内存位置,这意味着程序会生成内存分段错误并且需要错误恢复。

当程序试图从堆栈帧被溢出改变的函数返回时,它可能会变得不稳定甚至崩溃。

但是

1. 网络犯罪分子可以利用缓冲区溢出,用直接指向其恶意代码的有效内存位置覆盖返回地址,从而在许多情况下使他们能够启动 shell 并完全控制受害计算机。

2. 一些漏洞利用代码甚至巧妙地在执行恶意操作后修复堆栈损坏,以恢复原始返回地址。通过这种方式,攻击者试图混淆返回指令的劫持,让程序随后按预期运行。

上溢

下溢

 

代码(示例)

将十六进制字符编码为字节值

中兴通讯 MF971R LTE 路由器中漏洞的简化和重写版本,跟踪为CVE‑2021‑21748

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <stdio.h>
#include <string.h>
void encodeHexAsByteValues(const char *hexString, char *byteValues) {
signed int offset = 0;
int hexValues = 0;
int byte = 0;
while (offset < strlen(hexString)) {
        strncpy((char *) &hexValues, &hexString[2 * offset], 2u);
        sscanf((const char *) &hexValues, "%02X", &byte);
        byteValues[offset++] = byte;       // 通过打开插入漏洞代码的路径,可以覆盖返回地址
    }
}
int main(void) {
const char* hexString = "0123456789ABCDEF01234";
char byteValues[4];      
encodeHexAsByteValues(hexString, byteValues); // 在调用函数之前,没有大小检查来确保hextstring对于字节值来说不太长
return 0;
}

byteValues是全局变量,把返回地址给覆盖了。

上溢

下溢

 

缓解

防止缓冲区溢出攻击

现代编译器操作系统已经实施了多种机制来使缓冲区溢出攻击更难以执行。例如-堆栈随机化和堆栈损坏检测

堆栈随机化

缓冲区溢出攻击的成功部分依赖于知道指向漏洞利用代码的有效内存位置。过去,堆栈位置相当统一,因为相同的程序和操作系统版本组合将具有相同的堆栈地址。这意味着攻击者可以策划一次攻击——就像一种生物病毒一样——来攻击相同的程序操作系统组合。

堆栈随机化在程序执行开始时在堆栈上分配随机数量的空间。这个空间不是供程序使用的,而是允许程序在每次执行时有不同的堆栈地址。

然而,持续攻击者可以通过反复尝试不同的地址来克服堆栈随机化。

一种技术是在漏洞利用代码的开头使用一长串NOP(无操作)指令,这只会增加程序计数器。那么攻击者只需要猜测许多NOP指令中的任何一条的地址,而不必猜测漏洞利用代码开始的确切地址。这被称为“ NOP sled”,因为一旦程序跳转到这些NOP指令之一,它就会滑过其余的NOP,直到实际开始利用代码。例如,莫里斯蠕虫以 400 条NOP指令开始。

存在一整类称为地址空间布局随机化的技术,以确保程序的其他部分(如程序代码、库代码、全局变量和堆数据)在每次程序运行时具有不同的内存地址。

堆栈损坏检测

另一种防止缓冲区溢出攻击的方法是检测堆栈何时损坏。一种常见的机制称为堆栈保护器,它在堆栈帧的本地缓冲区和堆栈的其余部分之间插入一个随机Canary 值,也称为保护值.在从函数返回之前,程序可以检查 Canary 值的状态,如果缓冲区溢出改变了 Canary 值,则调用错误例程。

上溢

下溢

 

 


云涯历险记 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:漏洞学习:缓冲区溢出
喜欢 (1)