使用 c 的缓冲区溢出

Buffer Overflow using c

我正在尝试创建缓冲区溢出,它将用值“31337”覆盖变量 "b"。编译后的文件名为"bo",缓冲区大小为010,8字节,所以我用"AAAAAAAA"填充,31337十六进制为7A69。因此,Linux 中的以下命令在理论上应该有效但不成功:

printf 'AAAAAAAA\x69\x7A\x00\x00' | ./bo

上面的命令应该覆盖 "b" 变量。如果我将 b 变量更改为 1337 并将命令更改为以下内容,它就会起作用:

printf 'xxxxxxxx\x39\x05\x00\x00' | ./bo

1337 的十六进制为 539。

这是终端的命令结果

root@kali:~# printf 'AAAAAAAA\x69\x7A\x00\x00' | ./bo
1111638594

我预计 31337

root@kali:~# printf 'AAAAAAAA\x39\x05\x00\x00' | ./bo
1337

有人知道我做错了什么吗?对十六进制1337有效,对31337无效。以下是源码:

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>

int play()
{
    int a;
    int b;
    char buffer[010];
    a = 0x41414141;
    b = 0x42424242;

    if (read(STDIN_FILENO, &buffer, 0xC) < 0) 
        perror("read");

    printf("%d\n", b);
}


int main(int argc, char *argv[]){
    play();
    exit(EXIT_SUCCESS);
}

您不能假设变量将在堆栈上有特定位置。但是,有一种方法可以强制执行它。你可以这样做:

int play()
{
    struct {
        int a;
        char buffer[010];
        int b;
    } vars;

    vars.a = 0x41414141;
    vars.b = 0x42424242;

    if (read(STDIN_FILENO, &vars.buffer, 0xC) < 0) 
        perror("read");

    printf("%d\n", vars.b);
}

这将强制变量在内存中的顺序。当我尝试这样做时,它起作用了,但是当我切换顺序时

struct {
    int a;
    int b;
    char buffer[010];
} vars;

它没有。

虽然我不确定您可以信任或使用它多少。这只能保证&a<&buffer<&b。它不保证&(a+1)=&buffer。事实上,如果a是一个单字节类型的变量就不会这样了。

以下是订单重要性的示例:

int main()
{
    struct {
        char x;
        int a;
        char y;
    } v;

    struct {
        char x;
        char y;
        int a;
    } w;

    printf("%d\n", sizeof(v));
    printf("%d\n", sizeof(w));
}

输出:

$ ./a.out 
12
8

如果您对变量重新排序,结构的大小可能会发生变化,这是不允许编译器对它们重新排序的原因。