C语言 缓冲区溢出在 gdb 中有效,但并非没有它

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17775186/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 06:58:51  来源:igfitidea点击:

Buffer overflow works in gdb but not without it

csecuritybuffer-overflowfortify-sourcememory-safety

提问by thaweatherman

I am on CentOS 6.4 32 bit and am trying to cause a buffer overflow in a program. Within GDB it works. Here is the output:

我在 CentOS 6.4 32 位上并试图导致程序中的缓冲区溢出。在 GDB 中它有效。这是输出:

[root@localhost bufferoverflow]# gdb stack
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-60.el6_4.1)
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /root/bufferoverflow/stack...done.
(gdb) r
Starting program: /root/bufferoverflow/stack
process 6003 is executing new program: /bin/bash
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.107.el6_4.2.i686
sh-4.1#

However when I run the program stack just on its own it seg faults. Why might this be?

但是,当我单独运行程序堆栈时,它会出现段错误。为什么会这样?

回答by mavam

Exploit development can lead to serious headaches if you don't adequately account for factors that introduce non-determinisminto the debugging process. In particular, the stack addresses in the debugger may not match the addresses during normal execution. This artifact occurs because the operating system loader places both environment variables and program arguments beforethe beginning of the stack:

如果您没有充分考虑将不确定性引入调试过程的因素,则漏洞利用开发可能会导致严重的问题。特别是,调试器中的堆栈地址可能与正常执行期间的地址不匹配。出现此工件是因为操作系统加载程序在堆栈开始之前放置了环境变量和程序参数:

Process layout

工艺布局

Since your vulnerable program does not take any arguments, the environment variables are likely the culprit. Mare sure they are the same in both invocations, in the shell and in the debugger. To this end, you can wrap your invocation in env:

由于您的易受攻击的程序不接受任何参数,因此环境变量可能是罪魁祸首。确保它们在两次调用、shell 和调试器中都是相同的。为此,您可以将调用包装在env

env - /path/to/stack

And with the debugger:

并使用调试器:

env - gdb /path/to/stack
($) show env
LINES=24
COLUMNS=80

In the above example, there are two environment variables set by gdb, which you can further disable:

在上面的例子中,gdb设置了两个环境变量,你可以进一步禁用:

unset env LINES
unset env COLUMNS

Now show envshould return an empty list. At this point, you can start the debugging process to find the absolute stack address you envision to jump to (e.g., 0xbffffa8b), and hardcode it into your exploit.

现在show env应该返回一个空列表。此时,您可以开始调试过程以找到您想跳转到的绝对堆栈地址(例如,0xbffffa8b),并将其硬编码到您的漏洞利用程序中。

One further subtle but important detail: there's a difference between calling ./stackand /path/to/stack: since argv[0]holds the program exactly how you invoked it, you need to ensure equal invocation strings. That's why I used /path/to/stackin the above examples and not just ./stackand gdb stack.

另一个微妙但重要的细节:调用./stack/path/to/stack:之间存在差异,因为argv[0]保存程序正是您调用它的方式,您需要确保调用字符串相等。这就是为什么我/path/to/stack在上面的例子中使用而不仅仅是./stackand gdb stack

When learning to exploit with memory safety vulnerabilities, I recommend to use the wrapper program below, which does the heavy lifting and ensures equal stack offsets:

在学习利用内存安全漏洞时,我建议使用下面的包装程序,它可以完成繁重的工作并确保相等的堆栈偏移:

$ invoke stack         # just call the executable
$ invoke -d stack      # run the executable in GDB

Here is the script:

这是脚本:

#!/bin/sh

while getopts "dte:h?" opt ; do
  case "$opt" in
    h|\?)
      printf "usage: %s -e KEY=VALUE prog [args...]\n" $(basename 
env -i PWD="/root/Documents/MSec" SHELL="/bin/bash" SHLVL=0 /root/Documents/MSec/shelltest
env -i PWD="/root/Documents/MSec" SHELL="/bin/bash" SHLVL=0 gdb /root/Documents/MSec/shelltest
) exit 0 ;; t) tty=1 gdb=1 ;; d) gdb=1 ;; e) env=$OPTARG ;; esac done shift $(expr $OPTIND - 1) prog=$(readlink -f ) shift if [ -n "$gdb" ] ; then if [ -n "$tty" ]; then touch /tmp/gdb-debug-pty exec env - $env TERM=screen PWD=$PWD gdb -tty /tmp/gdb-debug-pty --args $prog "$@" else exec env - $env TERM=screen PWD=$PWD gdb --args $prog "$@" fi else exec env - $env TERM=screen PWD=$PWD $prog "$@" fi

回答by York

The address of stack frame pointer when running the code in gdb is different from running it normally. So you may corrupt the return address right in gdb mode, but it may not right when running in normal mode. The main reason for that is the environment variables differ among the two situation.

在gdb中运行代码时栈帧指针的地址与正常运行不同。因此,您可能会在 gdb 模式下损坏返回地址,但在正常模式下运行时可能不正确。主要原因是这两种情况的环境变量不同。

As this is just a demo, you can change the victim code, and print the address of the buffer. Then change your return address to offset+address of buffer.

由于这只是一个演示,您可以更改受害者代码,并打印缓冲区的地址。然后将您的返回地址更改为偏移量+缓冲区地址。

In reality, however,you need to guess the return address add NOP sledbefore your malicious code. And you may guess multiple times to get a correct address, as your guess may be incorrect.

但是,实际上,您需要在恶意代码之前猜测返回地址并添加NOP 雪橇。您可能会多次猜测以获得正确的地址,因为您的猜测可能不正确。

Hope this can help you.

希望这可以帮到你。

回答by Aralox

Here is a straightforward way of running your program with identical stacks in the terminal and in gdb:

这是在终端和 中使用相同堆栈运行程序的直接方法gdb

First, make sure your program is compiled without stack protection,

首先,确保你的程序是在没有堆栈保护的情况下编译的,

gcc -m32 -fno-stack-protector -z execstack -o shelltest shelltest.c -g

gcc -m32 -fno-stack-protector -z execstack -o shelltest shelltest.c -g

and and ASLR is disabled:

并且 ASLR 被禁用:

echo 0 > /proc/sys/kernel/randomize_va_space

echo 0 > /proc/sys/kernel/randomize_va_space

NOTE: default value on my machine was 2, note yours before changing this.

注意:我机器上的默认值是 2,在更改之前请注意您的。

Then run your program like so (terminal and gdb respectively):

然后像这样运行你的程序(分别是终端和 gdb):

show disable-randomization

Within gdb, make sure to unsetLINESand COLUMNS.

gdb,确保unsetLINESCOLUMNS

Note: I got those environment variables by playing around with a test program.

注意:我通过玩测试程序获得了这些环境变量。

Those two runs will give you identical pointers to the top of the stack, so no need for remote script shenanigans if you're trying to exploit a binary hosted remotely.

这两次运行将为您提供指向堆栈顶部的相同指针,因此如果您尝试利用远程托管的二进制文件,则无需使用远程脚本恶作剧。

回答by LogicG8

The reason your buffer overflow works under gdb and segfaults otherwise is that gdb disables address space layout randomization. I believe this was turned on by default in gdb version 7.

您的缓冲区溢出在 gdb 和段错误下工作的原因是 gdb 禁用地址空间布局随机化。我相信这是在 gdb 版本 7 中默认打开的。

You can check this by running this command:

您可以通过运行以下命令来检查这一点:

set disable-randomization on

And set it with

并将其设置为

set disable-randomization off

or

或者

int main(){
    int **temp = (int**)malloc(2*sizeof(int*)); //temp[0] and temp[1] are NULL in gdb, but not outside
    if (temp[0] != NULL){
        *temp[0] = 1; //segfault outside of gdb
    }
    return 0;
}

回答by RdlP

I have tried the solution accepted here and It doesn't work (for me). I knew that gdb added environment variables and for that reason the stack address doesn't match, but even removing that variables I can't work my exploit without gdb (I also tried the script posted in the accepted solution).

我已经尝试了这里接受的解决方案,但它不起作用(对我来说)。我知道 gdb 添加了环境变量,因此堆栈地址不匹配,但即使删除这些变量,如果没有 gdb,我也无法利用我的漏洞(我也尝试了已接受的解决方案中发布的脚本)。

But searching in the web I found other script that work for me: https://github.com/hellman/fixenv/blob/master/r.sh

但是在网上搜索我发现了其他对我有用的脚本:https: //github.com/hellman/fixenv/blob/master/r.sh

The use is basically the same that script in the accepted solution:

使用与已接受解决方案中的脚本基本相同:

  • r.sh gdb ./program [args] to run the program in gdb
  • r.sh ./program [args] to run the program without gdb
  • r.sh gdb ./program [args] 在 gdb 中运行程序
  • r.sh ./program [args] 在没有 gdb 的情况下运行程序

And this script works for me.

这个脚本对我有用。

回答by jww

I am on CentOS 6.4 32 bit and am trying to cause a buffer overflow in a program... However when I run the program stack just on its own it seg faults.

我在 CentOS 6.4 32 位上,并试图在程序中导致缓冲区溢出......但是,当我单独运行程序堆栈时,它会出现段错误。

You should also ensure FORTIFY_SOURCE is not affecting your results. The seg fault sounds like FORTIFY_SOURCE could be the issue because FORTIFY_SOURCE will insert "safer" function calls to guard against some types of buffer overflows. If the compiler can deduce destination buffer sizes, then the size is checked and abort()is called on a violation (i.e., your seg fault).

您还应该确保 FORTIFY_SOURCE 不会影响您的结果。段错误听起来像 FORTIFY_SOURCE 可能是问题,因为 FORTIFY_SOURCE 将插入“更安全”的函数调用以防止某些类型的缓冲区溢出。如果编译器可以推导出目标缓冲区大小,则检查大小并abort()在违规(即,您的段错误)时调用该大小。

To turn off FORTIFY_SOURCE for testing, you should compile with -U_FORTIFY_SOURCEor -D_FORTIFY_SOURCE=0.

要关闭 FORTIFY_SOURCE 进行测试,您应该使用-U_FORTIFY_SOURCE或 进行编译-D_FORTIFY_SOURCE=0

回答by chacham15

One of the main things that gdb does that doesnt happen outside gdb is zero memory. More than likely somewhere in the code you are not initializing your memory and it is getting garbage values. Gdb automatically clears all memory that you allocate hiding those types of errors.

gdb 所做的在 gdb 之外不会发生的主要事情之一是零内存。很可能在代码中的某个地方您没有初始化您的内存并且它正在获取垃圾值。Gdb 会自动清除您分配的所有内存以隐藏这些类型的错误。

For example: the following should work in gdb, but not outside it:

例如:以下应该在 gdb 中工作,但不能在它之外:

##代码##

Try running your program under valgrind to see if it can detect this issue.

尝试在 valgrind 下运行您的程序,看看它是否可以检测到此问题。