我现在正在玩io-wargames,很有趣,级别3:

我确实理解为什么这段代码(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字节。

评论

这是玩游戏的人的主要破坏者,您是否可以考虑删除实际漏洞并在适当的地方添加破坏者标签?

@ 0xea我删除了显式漏洞利用。谢谢

#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