【问题标题】:Is there a buffer overflow helloworld for c++?c++ 是否存在缓冲区溢出 helloworld?
【发布时间】:2011-02-01 18:13:59
【问题描述】:

我试过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

【问题讨论】:

  • 您想要产生缓冲区溢出的简单代码,还是利用缓冲区溢出的简单代码?因为你得到的大多数答案只是告诉你如何溢出缓冲区,我认为这不是很有趣。
  • 如果您不向我们提供更多信息,更新将毫无帮助...
  • 这是@Dan要求的,看这个帖子下的cmets:stackoverflow.com/questions/2533261/…

标签: c++ buffer-overflow


【解决方案1】:

这将有助于将另一个问题中的示例编译为汇编,这样您就可以了解给定编译器和处理器的堆栈布局方式。示例中的 +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

【讨论】:

  • 为什么我的电脑不能正常工作?
  • 编辑您的问题以显示示例在编译为汇编时的样子,我们可以看看。只需要看看foo的样子。
  • @Mask:因为这完全取决于编译器、架构、堆栈布局、调用约定等等。由于此类漏洞利用了未定义的行为,因此不能期望它在所有系统上都按原样工作。
  • @Dan ,我不知道如何显示装配图...我已经粘贴了 makefile 我正在使用 tho
  • 如果您使用 gcc,则使用 -S 开关进行编译。如果您使用的是其他编译器,请阅读文档 :)
【解决方案2】:

您可以使用您发布的 C 示例。它在 C 和 C++ 中的工作方式相同。

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

int main() {
    return ""[1]; // Undefined behaviour (reading past '\0' in string)
}

【讨论】:

  • 我尝试了该代码,但不起作用。顺便说一句,您的代码似乎无法编译:来自char*' to int'的无效转换
  • @Mask,请记住,访问未分配的内存或指针之外的内存是未定义的行为。它可能会崩溃、什么也不做,或者让您的计算机着火。我修复了编译器错误;我的错。
  • @UncleBens:当你测试它时它恰好是 0,还是这实际上是标准化的、定义的行为?
  • 数组末尾的一个,即 arr[sizeof(arr)],不能保证为 0,但我经常看到这样的实现。这部分源于这样一个事实,即实现需要确保指向数组后面一个元素的指针是唯一的。不过,取消引用该元素仍然是未定义的行为。
  • main 函数 (3.6.1 / 2) 的描述说:“argv[argc] 的值应为 0。”它不是数组末尾的一个。
【解决方案3】:

这样的?

int main()
{
    char arr[1];
    arr[1000000] = 'a';
}

【讨论】:

    【解决方案4】:

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

    #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中的字符”

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

    【讨论】:

      【解决方案5】:
      #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 /管理员)。

      http://en.wikipedia.org/wiki/Buffer_overflow 阅读更多信息。

      【讨论】:

        【解决方案6】:

        除了excellent article pointed out by Eric,您还可以查看以下阅读材料:

        以下文章更侧重于堆溢出:

        这是从我的回答 here 复制而来的。

        【讨论】:

        • 你能详细说明一下shell代码部分吗?我知道如何更改ret地址,但似乎无法理解shell代码漏洞如何在所有tutos中工作......跨度>
        • 在这些教程中,返回地址被修改为指向 shellcode 或指向 shellcode 的 NOP 幻灯片。 shellcode 是要执行的代码,通常用机器代码编写。它特定于目标 OS/CPU 组合并经过精心设计,因此不包含任何 NULL 字符。它通常以 JMP 开头,指向 shellcode 中的另一个点,然后是 CALL 以调用有效负载的开头。
        • 所以要想成功利用,关键是修改返回地址指向shellcode,如果程序不是开源的,是不是很难做到?
        • 发现和利用安全漏洞并非易事,也不应该如此。了解这些漏洞利用的基础知识对于编写代码来防御它们很重要。您可能对 Shellcoder 手册 感兴趣 - amazon.com/Shellcoders-Handbook-Discovering-Exploiting-Security/…
        【解决方案7】:

        buffer overflow 一词恰恰意味着访问超过缓冲区的末尾(草率地需要包含 buffer underflow 的概念)。但是有一整类“内存安全问题”与缓冲区溢出、指针、数组、分配和释放有关,所有这些都可能在代码中产生崩溃和/或利用机会。看到这个C example of another memory safety problem (and our way to detect it).

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-02-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-09-07
          • 1970-01-01
          相关资源
          最近更新 更多