我在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#
然而,当我自己运行程序堆栈时它会出现故障。为什么会这样?
答案 0 :(得分:91)
如果您没有充分考虑将非确定性引入调试过程的因素,那么漏洞利用开发可能会导致严重的问题。特别是,调试器中的堆栈地址可能与正常执行期间的地址不匹配。发生此工件是因为操作系统加载程序在堆栈开头之前放置了环境变量和程序参数:
由于易受攻击的程序不接受任何参数,因此环境变量可能是罪魁祸首。确保它们在调用,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
而不只是./stack
和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
答案 1 :(得分:7)
在gdb中运行代码时堆栈帧指针的地址与正常运行它不同。因此,您可能会在gdb模式下损坏返回地址,但在正常模式下运行时可能不正确。主要原因是两种情况下环境变量不同。
由于这只是一个演示,您可以更改受害者代码,并打印缓冲区的地址。然后将返回地址更改为偏移量+缓冲区地址。
但实际上,您需要在恶意代码之前猜测返回地址添加NOP sled。并且您可能会多次猜测以获得正确的地址,因为您的猜测可能不正确。
希望这可以帮到你。
答案 2 :(得分:6)
缓冲区溢出在gdb和segfaults下工作的原因是gdb禁用地址空间布局随机化。我相信这在gdb版本7中默认打开。
您可以通过运行以下命令来检查:
show disable-randomization
并设置
set disable-randomization on
或
set disable-randomization off
答案 3 :(得分:5)
以下是在终端和PlaygroundPage.current.liveView = canvas
中使用相同堆栈运行程序的简单方法:
首先,确保编译程序没有堆栈保护,
gdb
和ASLR已禁用:
gcc -m32 -fno-stack-protector -z execstack -o shelltest shelltest.c -g
注意:我的机器上的默认值是2,请在更改之前注明。
然后像这样运行程序(终端和gdb):
echo 0 > /proc/sys/kernel/randomize_va_space
在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
和LINES
。
注意:我通过使用test program来获取这些环境变量。
这两个运行将为您提供指向堆栈顶部的相同指针,因此如果您尝试利用远程托管的二进制文件,则不需要远程脚本恶作剧。
答案 4 :(得分:2)
我已经尝试过这里接受的解决方案,它不起作用(对我来说)。我知道gdb添加了环境变量,因此堆栈地址不匹配,但即使删除了这些变量,我也可以在没有gdb的情况下使用我的漏洞(我也尝试过在已接受的解决方案中发布的脚本)。
但是在网上搜索我找到了适合我的其他脚本:https://github.com/hellman/fixenv/blob/master/r.sh
使用与接受的解决方案中的脚本基本相同:
这个脚本适合我。
答案 5 :(得分:1)
我在CentOS 6.4 32位上试图在程序中导致缓冲区溢出...但是当我自己运行程序堆栈时它会出现故障。
您还应该确保FORTIFY_SOURCE不会影响您的结果。因为FORTIFY_SOURCE会插入更安全的#34;函数调用以防止某些类型的缓冲区溢出。如果编译器可以推导出目标缓冲区大小,则会检查大小并在违规时调用abort()
(即,您的seg错误)。
要关闭FORTIFY_SOURCE进行测试,您应该使用-U_FORTIFY_SOURCE
或-D_FORTIFY_SOURCE=0
进行编译。
答案 6 :(得分: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下运行程序,看看它是否可以检测到这个问题。