我是道德黑客世界的新手,最重要的事情之一是堆栈溢出,无论如何我编写了一个有 char name [400] 语句的易受攻击的 C 程序,当我尝试使用 401A 运行程序时它没有'不会溢出,但是我正在关注的书说它必须溢出并且逻辑意义上说是这样,所以出了什么问题???
4 回答
如果你定义了一个缓冲区:
char buf[400];
并写入 401 字节,缓冲区已溢出。但是,其余的取决于您的代码结构:
- 缓冲区是如何分配的(静态、动态、在堆栈上)
- 在记忆中之前和之后发生了什么
- 您的架构的调用约定和 ABI(如果是堆栈缓冲区)
- 多一点...
事情比看起来更复杂。引用维基百科:
在计算机安全和编程中,缓冲区溢出或缓冲区溢出是一种异常情况,其中进程将数据存储在程序员为其预留的内存之外的缓冲区中。额外的数据会覆盖相邻的内存,其中可能包含其他数据,包括程序变量和程序流控制数据。这可能会导致程序行为不稳定,包括内存访问错误、不正确的结果、程序终止(崩溃)或违反系统安全性。
请注意此引用中可能出现的多个实例。所有这一切都可能发生,也可能不会发生。同样,这取决于其他因素。
C 不检查缓冲区溢出(溢出缓冲区是未定义的行为)。通常系统只会允许您(和黑客)在缓冲区之外进行写入,这就是缓冲区溢出易受攻击的原因。
例如,如果代码是
char name[400];
char secret_password[400];
...
内存可以布局为
[John ][12345 ]
name secret_password
现在,如果您将 401A
后跟 NULL 写入name
,则额外A\0
内容将写入secret_password
,这基本上将密码从您的行李组合更改为“A”:
[AAAAAAAAA...AAAAA][A␀345 ]
name secret_password
这是 C 语言中的一个很好的示例,展示了如何使用缓冲区溢出来执行任意代码。它的目标是找到一个输入字符串,该字符串将覆盖导致目标函数执行的返回地址。
对于缓冲区溢出的一个很好的解释,我推荐编写安全代码第 2 版的第 5 章。
有关缓冲区溢出的其他有用信息:
- 安全程序员:对抗缓冲区溢出 David Wheeler
- 为了乐趣和利润而粉碎堆栈Phrack 杂志的经典文章
Stackoverflow 和 bufferoverflow 是不同的概念。
Stackoverflow:
程序堆栈的大小是静态的,它在运行时永远不会改变。由于无法知道您的堆栈在运行时需要多少内存,因此保留了一个合理的大内存块。然而,一些程序通过调用递归函数来执行此操作。
函数调用保留了在堆栈上存储本地变量所需的空间,并在退出后释放内存。递归函数将在每次进入时保留新内存,并在退出时释放它。如果递归由于编程错误而永远不会结束,则在堆栈上保留越来越多的内存,直到堆栈满为止。
尝试在完整堆栈上保留内存将导致错误,即 stackoverflow。
示例代码:
volatile bool args = false;
int myoverflow(int i){
int a[500];
if(args)
return a[i%500];
else
return myoverflow(i+1);
}
这应该溢出堆栈。每次进入函数都会保留 500 * sizeof(int) 。
Bufferoverflow:
你有两个变量,一个数组 a 和一个数组 b。a 可以容纳 4 个元素,b 可以容纳 2 个。现在您将 5 个元素写入 a,第 5 个元素落在 b 中。
例子:
void main(int ,char**)
{
int a[4];
int b[2];
a[5] = 22;
std::cout<<b[0];
}
这应该打印 22。它将在 a 之外写入 b 使用的内存。
注意:我的示例函数都不能保证工作,编译器可以自由地优化函数调用并根据需要安排堆栈上使用的内存。它甚至可能在数组 a 越界访问内存时打印编译错误。