我是否总是必须覆盖 EIP 才能在缓冲区溢出时写入堆栈?

信息安全 开发 缓冲区溢出 外壳代码
2021-09-06 05:02:16

我是否总是必须覆盖 EIP 才能在缓冲区溢出时写入堆栈?内存是如何组织的?我用谷歌找不到合适的图表

2个回答

您不必总是覆盖返回地址以利用基于堆栈的缓冲区溢出(也有一个很好的堆栈布局图)。使用基于堆栈的缓冲区溢出,您可以破坏在函数的本地范围内声明的其他变量,这会产生有趣的结果。

例如,假设有一个身份验证功能:

//I like to think of the return address as sitting on top of every function.
//void * ret;
boolean login(char * password){
  boolean is_logged_in=False;
  char buf[5];
  strcpy(buf,password);
  if(strmp(buf, MASTER_PASSWORD)==0){
     is_Logged_int=True;
  }
  return is_logged_in;
}

堆栈布局is_logged_in位于 buf 之上。包含返回地址的堆栈帧在上面的某处is_logged_in仅当函数返回时,返回地址才会成为 EIP。但是攻击者没有必要破坏堆栈帧以便攻击者利用这个缓冲区溢出。is_logged_in简单地用等于的值覆盖的值True将允许攻击者在不知道 的值的情况下进行身份验证MASTER_PASSWORD

在这个缓冲区溢出漏洞中,使用:ASLR、NX Zones 和 Stack Canaries 并不能阻止利用。事实上,无论平台如何(windows/linux/arm/x86...),同样的漏洞利用也可能会起作用。

(免责声明:我想我在“黑客:剥削的艺术”中读到了这种利用方法)

反之亦然:溢出堆栈缓冲区,以便在函数返回时覆盖将加载 EIP 的字段。

在通常的体系结构中,堆栈向下增长,因此在调用函数时压入堆栈的“返回地址”位于局部变量之后几个字节通过溢出本地缓冲区,您可以覆盖 RAM 中的内容,即返回地址。当函数返回时,相应的ret操作码会将返回地址加载到 EIP 中,这意味着执行会跳转到该地址。