栈缓冲区溢出

栈缓冲区溢出（stack buffer overflow或stack buffer overrun）是计算机程序把数据写入调用栈上的内存时超出了数据结构的边界。栈缓冲区溢出是缓冲区溢出的一种。 这会损坏相邻数据的值，引发程序崩溃或者修改了函数返回地址从而导致执行恶意的程序。这种攻击方式称为stack smashing。可被用于注入可执行代码、接管进程的执行。是最为古老的黑客攻击行为之一。

例子
下例可用于覆盖函数返回地址。 通过函数 strcpy() :

#include <string.h>

void foo (char *bar)
{
   char  c[12];

   strcpy(c, bar);  // no bounds checking
}

int main (int argc, char **argv)
{
   foo(argv[1]);

   return 0;
}

当命令行参数少于12个字符时（例子B时）该程序是安全的。  

foo()函数的不同输入下的调用栈:

例子C中, 命令行参数多于11个字符，导致foo()覆盖了本地调用栈的数据、存储的栈指针（EBP）以及最重要的返回地址。 

攻击也可以修改内部变量值：
#include <string.h>
#include <stdio.h>

void foo (char *bar)
{
   float My_Float = 10.5; // Addr = 0x0023FF4C
   char  c[28];           // Addr = 0x0023FF30

   // Will print 10.500000
   printf("My Float value = %f\n", My_Float);

    /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       Memory map:
       @ : c allocated memory
       # : My_Float allocated memory

           *c                      *My_Float
       0x0023FF30                  0x0023FF4C
           |                           |
           @@@@@@@@@@@@@@@@@@@@@@@@@@@@#####
      foo("my string is too long !!!!! XXXXX");

   memcpy will put 0x1010C042 (little endian) in My_Float value.
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

   memcpy(c, bar, strlen(bar));  // no bounds checking...

   // Will print 96.031372
   printf("My Float value = %f\n", My_Float);
}

int main (int argc, char **argv)
{
   foo("my string is too long !!!!! \x10\x10\xc0\x42");
   return 0;
}

平台相关

保护方式
常用三种方式来对抗栈缓冲区溢出攻击。

检查栈缓冲区溢出的发生 
栈的警惕标志（stack canary），得名于，用于探测该灾难的发生。具体办法是在栈的返回地址的存储位置之前放置一个整形值，该值在装入程序时随机确定。栈缓冲区攻击时从低地址向高地址覆盖栈空间，因此会在覆盖返回地址之前就覆盖了警惕标志。返回返回前会检查该警惕标志是否被篡改。

栈数据不可执行 
采取了“写异或执行”策略（, "Write XOR Execute"），即内存要么可写，要么可执行，但二者不能兼得。这是最常用的方法，大部分桌面处理器都硬件支持不可执行标志（no-execute flag）。

随机化内存空间布局

著名例子
莫里斯蠕虫针对Unix  服务器. 
 .
 针对Microsoft SQL Server. 
衝擊波蠕蟲 针对微软的DCOM 服务.
针对Wii

参见

参考文献

程式錯誤