50

我在 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#

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

4

7 回答 7

129

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

流程布局

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

env - /path/to/stack

并使用调试器:

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

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

unset env LINES
unset env COLUMNS

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

另一个微妙但重要的细节:调用./stack和之间存在区别/path/to/stack:由于argv[0]程序完全按照您调用它的方式保存,因此您需要确保调用字符串相等。这就是我/path/to/stack在上面的例子中使用的原因,而不仅仅是./stackand gdb stack

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

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

这是脚本:

#!/bin/sh

while getopts "dte:h?" opt ; do
  case "$opt" in
    h|\?)
      printf "usage: %s -e KEY=VALUE prog [args...]\n" $(basename $0)
      exit 0
      ;;
    t)
      tty=1
      gdb=1
      ;;
    d)
      gdb=1
      ;;
    e)
      env=$OPTARG
      ;;
  esac
done

shift $(expr $OPTIND - 1)
prog=$(readlink -f $1)
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
于 2013-07-21T19:20:46.197 回答
10

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

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

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

希望这可以帮到你。

于 2015-04-10T10:57:47.170 回答
10

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

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

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

并且 ASLR 被禁用:

echo 0 > /proc/sys/kernel/randomize_va_space

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

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

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

在 内gdb,确保unset LINESCOLUMNS

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

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

于 2017-03-30T05:32:13.713 回答
7

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

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

show disable-randomization

并将其设置为

set disable-randomization on

或者

set disable-randomization off
于 2013-07-21T18:10:51.847 回答
4

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

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

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

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

这个脚本对我有用。

于 2016-10-12T15:58:13.100 回答
1

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

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

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

于 2014-09-12T12:41:11.760 回答
0

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

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

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;
}

尝试在 valgrind 下运行你的程序,看看它是否能检测到这个问题。

于 2013-07-21T18:04:50.637 回答