我确实理解为什么这段代码
(strlen(argv[1])
会出现堆栈溢出),但是我不明白的是为什么它会溢出功能指针functionpointer
。 functionpointer
在堆栈上的char buffer[50];
之前声明,所以它怎么覆盖它? 这是主要的易受攻击的代码:
int main(int argc, char **argv, char **envp)
{
void (*functionpointer)(void) = bad;
char buffer[50];
if(argc != 2 || strlen(argv[1]) < 4)
return 0;
memcpy(buffer, argv[1], strlen(argv[1]));
memset(buffer, 0, strlen(argv[1]) - 4);
printf("This is exciting we're going to %p\n", functionpointer);
functionpointer();
return 0;
}
这是外壳利用stackoverflow的代码:
level3@io:~$ /levels/level03 11111111
This is exciting we're going to 0x80484a4
I'm so sorry, you're at 0x80484a4 and you want to be at 0x8048474
level3@io:~$ /levels/level03 111111111111111111111111111111111111111111111111111111111111111111111111111111111
This is exciting we're going to 0x31313100
Segmentation fault
<这是可执行文件的objump -d
:080484c8 <main>:
80484c8: 55 push %ebp
80484c9: 89 e5 mov %esp,%ebp
80484cb: 83 ec 78 sub q4312078qx78,%esp
80484ce: 83 e4 f0 and q4312078qxfffffff0,%esp
80484d1: b8 00 00 00 00 mov q4312078qx0,%eax
80484d6: 29 c4 sub %eax,%esp
80484d8: c7 45 f4 a4 84 04 08 movl q4312078qx80484a4,-0xc(%ebp)
80484df: 83 7d 08 02 cmpl q4312078qx2,0x8(%ebp)
80484e3: 75 17 jne 80484fc <main+0x34>
80484e5: 8b 45 0c mov 0xc(%ebp),%eax
80484e8: 83 c0 04 add q4312078qx4,%eax
80484eb: 8b 00 mov (%eax),%eax
80484ed: 89 04 24 mov %eax,(%esp)
80484f0: e8 a7 fe ff ff call 804839c <strlen@plt>
80484f5: 83 f8 03 cmp q4312078qx3,%eax
80484f8: 76 02 jbe 80484fc <main+0x34>
80484fa: eb 09 jmp 8048505 <main+0x3d>
80484fc: c7 45 a4 00 00 00 00 movl q4312078qx0,-0x5c(%ebp)
8048503: eb 74 jmp 8048579 <main+0xb1>
8048505: 8b 45 0c mov 0xc(%ebp),%eax
8048508: 83 c0 04 add q4312078qx4,%eax
804850b: 8b 00 mov (%eax),%eax
804850d: 89 04 24 mov %eax,(%esp)
8048510: e8 87 fe ff ff call 804839c <strlen@plt>
8048515: 89 44 24 08 mov %eax,0x8(%esp)
8048519: 8b 45 0c mov 0xc(%ebp),%eax
804851c: 83 c0 04 add q4312078qx4,%eax
804851f: 8b 00 mov (%eax),%eax
8048521: 89 44 24 04 mov %eax,0x4(%esp)
8048525: 8d 45 a8 lea -0x58(%ebp),%eax
8048528: 89 04 24 mov %eax,(%esp)
804852b: e8 5c fe ff ff call 804838c <memcpy@plt>
8048530: 8b 45 0c mov 0xc(%ebp),%eax
8048533: 83 c0 04 add q4312078qx4,%eax
8048536: 8b 00 mov (%eax),%eax
8048538: 89 04 24 mov %eax,(%esp)
804853b: e8 5c fe ff ff call 804839c <strlen@plt>
8048540: 83 e8 04 sub q4312078qx4,%eax
8048543: 89 44 24 08 mov %eax,0x8(%esp)
8048547: c7 44 24 04 00 00 00 movl q4312078qx0,0x4(%esp)
804854e: 00
804854f: 8d 45 a8 lea -0x58(%ebp),%eax
8048552: 89 04 24 mov %eax,(%esp)
8048555: e8 02 fe ff ff call 804835c <memset@plt>
804855a: 8b 45 f4 mov -0xc(%ebp),%eax
804855d: 89 44 24 04 mov %eax,0x4(%esp)
8048561: c7 04 24 c0 86 04 08 movl q4312078qx80486c0,(%esp)
8048568: e8 3f fe ff ff call 80483ac <printf@plt>
804856d: 8b 45 f4 mov -0xc(%ebp),%eax
8048570: ff d0 call *%eax
8048572: c7 45 a4 00 00 00 00 movl q4312078qx0,-0x5c(%ebp)
8048579: 8b 45 a4 mov -0x5c(%ebp),%eax
804857c: c9 leave
804857d: c3 ret
804857e: 90 nop
804857f: 90 nop
我看到编译器保留在主程序的序言中本地主要功能变量的功能帧
0x78
字节。 #1 楼
编译器确实将函数指针放在缓冲区之后。在反汇编中,检查
memcpy
调用:8048525: lea -0x58(%ebp),%eax
8048528: mov %eax,(%esp)
804852b: call 804838c <memcpy@plt>
memcpy
的第一个参数(缓冲区的地址)在[esp+0]
处,您可以看到ebp-0x58
的值正放在其中。下一个是函数结尾处的函数调用:
804856d: mov -0xc(%ebp),%eax
8048570: call *%eax
您可以看到正在跳转到的地址是从
[ebp-0xc]
加载的,它是字符缓冲区开头之后的0x4c(76)字节。希望可以使情况变得更清楚的IDA:-00000058 buffer db 76 dup(?)
-0000000C functionpointer dd ?
-00000008 var_8 dd ?
-00000004 var_4 dd ?
+00000000 s db 4 dup(?)
+00000004 r db 4 dup(?)
+00000008 argc dd ?
+0000000C argv dd ?
最左边一栏中的偏移量是相对于ebp的。内存地址向下增加,因此很明显,向
buffer
中写入过多数据将覆盖函数指针(然后返回地址)。放在所有其他变量之后:评论
IDA如何在输出中附带功能指针和缓冲区?
– 0x90
13年6月8日在21:45
@ 0x90:很明显,我重命名了它们:)尽管如果存在DWARF信息(自6.4起),它可能会自动发生。
–伊戈尔·斯科钦斯基♦
2013年6月8日22:02
#2 楼
函数指针在char缓冲区[50]之前声明;
对象在堆栈中的顺序是实现定义的。 C没有提到任何堆栈,堆栈的增长方向也是实现定义的(通常它向下增长,但是在某些系统中它向上增长)。
在您的情况下,可能先放置
functionpointer
,然后再放置buffer
。由于系统中堆栈变得越来越糟,这使您在溢出functionpointer
时覆盖buffer
。#3 楼
为什么即使在易受攻击的缓冲区之前声明了函数指针,还是会覆盖函数指针?
在易受攻击的代码中声明的顺序是:
void (*functionpointer)(void) = bad;
char buffer[50];
汇编代码向我们展示了函数指针变量位于
ebp-0xc
处,缓冲区位于ebp-0x58
处。 这证明了在此系统中,由于缓冲区的位置比函数指针变量的地址低,堆栈正在向下增长(至较低的地址)。
该系统中堆栈向下增长的另一个证明是以下指令,该指令通过减去
esp
来分配所需的空间:80484cb: 83 ec 78 sub 0x003FFFA8 buffer
...
0x003FFFF4 function pointer
0x003FFFF8
0x003FFFFC
0x00400000 saved ebp
0x00400004 saved return address
x78,%esp
现在
memcpy
从位于num
的字节开始复制ebp-0x58
字节,然后继续递增。指针位于1
。ebp-0x58
拥有一个地址,比方说ebp-0x57
,所以num
是地址memcpy
从该地址开始递增,您最终将到达ebp-0xc
。q4312078q
评论
这是玩游戏的人的主要破坏者,您是否可以考虑删除实际漏洞并在适当的地方添加破坏者标签?@ 0xea我删除了显式漏洞利用。谢谢