2

我尝试了this question提供的代码,但它不起作用。

如何设计一个溢出来包裹我的头?

更新:

    .file   "hw.cpp"
    .section .rdata,"dr"
LC0:
    .ascii "Oh shit really bad~!\15\12\0"
    .text
    .align 2
.globl __Z3badv
    .def    __Z3badv;   .scl    2;  .type   32; .endef
__Z3badv:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $8, %esp
    movl    $LC0, (%esp)
    call    _printf
    leave
    ret
    .section .rdata,"dr"
LC1:
    .ascii "WOW\0"
    .text
    .align 2
.globl __Z3foov
    .def    __Z3foov;   .scl    2;  .type   32; .endef
__Z3foov:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $4, %esp
    movl    LC1, %eax
    movl    %eax, -4(%ebp)
    movl    $__Z3badv, 4(%ebp)
    leave
    ret
    .def    ___main;    .scl    2;  .type   32; .endef
    .align 2
.globl _main
    .def    _main;  .scl    2;  .type   32; .endef
_main:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $8, %esp
    andl    $-16, %esp
    movl    $0, %eax
    addl    $15, %eax
    addl    $15, %eax
    shrl    $4, %eax
    sall    $4, %eax
    movl    %eax, -4(%ebp)
    movl    -4(%ebp), %eax
    call    __alloca
    call    ___main
    call    __Z3foov
    movl    $0, %eax
    leave
    ret
    .def    _printf;    .scl    2;  .type   32; .endef
4

7 回答 7

3

您可以使用您发布的 C 示例。它在 C 中的工作原理与 C++ 相同。

我能想到的最小可读答案:

int main() {
    return ""[1]; // Undefined behaviour (reading past '\0' in string)
}
于 2010-03-28T14:37:50.467 回答
3

将另一个问题中的示例编译到汇编中会有所帮助,这样您就可以了解给定编译器和处理器的堆栈布局方式。示例中的+8可能不是您环境的正确数字。您需要确定的是返回地址存储在堆栈中相对于存储在堆栈中的数组的位置。

顺便说一句,这个例子对我有用。我在 Win XP 上用 Cygwin 编译,gcc 版本 4.3.4。当我说它“有效”时,我的意思是它在函数中运行代码bad(),即使该函数从未被代码调用。

$ gcc -Wall -Wextra buffer-overflow.c && ./a.exe
Oh shit really bad~!
Segmentation fault (core dumped)

该代码实际上不是缓冲区溢出的示例,它是利用缓冲区溢出时可能发生的坏事的示例。

我对 x86 汇编不是很好,但这是我对这个漏洞如何工作的解释。

$ gcc -S buffer-overflow.c && cat buffer-overflow.s
_foo:
        pushl   %ebp           ;2
        movl    %esp, %ebp     ;3
        subl    $16, %esp      ;4
        movl    LC1, %eax      ;5
        movl    %eax, -4(%ebp) ;6
        leal    -4(%ebp), %eax ;7
        leal    8(%eax), %edx  ;8
        movl    $_bad, %eax    ;9
        movl    %eax, (%edx)   ;10
        leave
        ret

_main:
    ...
        call    _foo            ;1
    ...

main调用foo(1) 时,call指令将 main 中的地址压入堆栈,以便在调用foo完成后返回。压入堆栈涉及递减 ESP 并在其中存储一个值。

一旦进入foo,旧的基指针值也被压入堆栈 (2)。这将在返回时foo恢复。堆栈指针被保存为此堆栈帧 (3) 的基指针。堆栈指针减 16 (4),这会在此堆栈帧上为局部变量创建空间。

文字“WOW\0”的地址被复制到overme堆栈上的局部变量中(5,6)——这对我来说似乎很奇怪,不应该将 4 个字符复制到堆栈上分配的空间中吗?无论如何,WOW(或指向它的指针)被复制的位置是当前基指针下方的 4 个字节。所以堆栈包含这个值,然后是旧的基指针,然后是返回地址。

的地址overme被放入 EAX (7) 并在该地址 (8) 之外的 8 个字节处创建一个整数指针。函数的地址bad被放入 EAX (9),然后该地址存储在整数指针 (10) 指向的内存中。

堆栈如下所示:

     // 4 bytes on each row
ESP: (unused)
   : (unused)
   : (unused)
   : &"WOW\0"
   : old EBP from main
   : return PC, overwritten with &bad

当您使用优化进行编译时,所有有趣的东西都会被优化为“无用代码”(确实如此)。

$ gcc -S -O2 buffer-overflow.c && cat buffer-overflow.s
_foo:
        pushl   %ebp
        movl    %esp, %ebp
        popl    %ebp
        ret
于 2010-03-28T15:02:16.897 回答
2

像这样的东西?

int main()
{
    char arr[1];
    arr[1000000] = 'a';
}
于 2010-03-28T14:56:20.173 回答
2

一个简单的缓冲区溢出将是这样的:

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

int main() {
   char a[4] = {0};
   char b[32] = {0};

   printf("before: b == \"%s\"\n", b);

   strcpy(a, "Putting too many characters in array a");

   printf("after:  b == \"%s\"\n", b);
}

一个可能的输出:

之前:b ==“”
之后:b ==“数组a中的字符”

程序的实际行为是未定义的,因此缓冲区溢出也可能导致不同的输出、崩溃或根本没有可观察到的效果。

于 2010-03-28T15:01:40.070 回答
0
#define _WIN32_WINNT 0x0400
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

void process_msg(const char *pSrc)
{
    char cBuff[5];
    strcpy(cBuff, pSrc);
}

void main()
{
    char szInput[] = "hello world!";
    process_msg(szInput);
}

在调试模式下在 Visual Studio 2008 中运行此程序会显示以下消息:

Run-Time Check Failure #2 - Stack around the variable 'cBuff' was corrupted.

在本例中,'cBuff' 字符数组分配在堆栈上,大小为 5 个字节。将给定指针的数据 (pSrc) 复制到该 char arrat (cBuff) 会覆盖堆栈帧的数据,这将导致可能的漏洞利用。

黑客使用了这种技术——他们发送一个特制的字符数组,它将覆盖堆栈上指向“返回”地址的指针,并将其更改为内存中所需的位置。

因此,例如,他们可以将该“返回”地址指向将打开端口或建立连接的任何系统/程序代码,然后他们会以应用程序的权限(很多时候这意味着 root/管理员)到达您的 PC .

在http://en.wikipedia.org/wiki/Buffer_overflow阅读更多内容。

于 2010-03-28T15:16:57.257 回答
0

除了Eric 指出的优秀文章之外,您还可以查看以下阅读材料:

以下文章更关注堆溢出:

这是从我在这里的回答中复制的。

于 2010-03-28T17:57:48.220 回答
0

术语缓冲区溢出精确地意味着访问超过缓冲区的末尾(草率地需要包括缓冲区下溢的概念)。但是有一整类“内存安全问题”与缓冲区溢出、指针、数组、分配和释放有关,所有这些都可能在代码中产生崩溃和/或利用机会。请参阅另一个内存安全问题的 C 示例(以及我们检测它的方法)。

于 2011-03-10T15:16:20.043 回答