我有一个程序,被告知要利用缓冲区溢出攻击。 据我所知,当我们将一个变量移动到另一个变量时,例如调用gets、strcmp等函数时,我们没有进行边界检查,就会发生缓冲区溢出。但是,我用了几天时间,还是没有弄清楚我程序的漏洞在哪里。有人可以给我一些开始的提示,或者我如何寻找易受缓冲区溢出攻击的变量?非常感谢。
下面是代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/sha.h>
#include <stdbool.h>
#include <unistd.h>
#include <fcntl.h>
#define DEFAULT_GAME 0
unsigned int credits;
void game_1();
void game_2();
void set_credits();
void change_game();
void (*games[2]) () = {game_1, game_2};
void (*admin_functionality[2]) () = {change_game, set_credits};
int current_game = 0;
void read_string(unsigned char *buf, unsigned int len){
unsigned int i = 0;
char c = 0;
while (i < len && (c != '\n' || i == 0)){
c = getchar();
if (c == EOF){
puts("SOMETHING WENT WRONG!");
exit(0);
} else if (c != '\n') {
buf[i++] = c;
}
}
}
int read_int(){
int input;
fflush(stdin);
if (scanf("%d", &input) != 1) {
puts("SOMETHING WENT WRONG");
exit(1);
}
return input;
}
int read_int_prompt(const char* prompt){
printf("%s", prompt);
return read_int();
}
void
initialize_seed(void) {
unsigned int seed;
int fd;
fd = open("/dev/urandom", O_RDONLY);
if (fd < 0) {
fprintf(stderr, "Lost my wisdom, I have. Now will I rest, yes, forever sleep.\n");
exit(1);
}
read(fd, &seed, sizeof(unsigned int));
close(fd);
srand(seed);
}
void read_flag(){
unsigned char content[128];
FILE *file;
file = fopen("./flag", "r");
if (file != NULL) {
fscanf(file, "%s", content);
fclose(file);
printf("You seized the opportunity and stole some secrets: %s\n", content);
} else {
fprintf(stderr, "Error while opening the file.\n");
exit(1);
}
return;
}
void print_banner(){
printf("Credits: %d\n", credits);
}
void print_menu(){
print_banner();
puts("1) Play");
puts("2) Administration");
puts("3) Exit");
}
void set_credits() {
printf("\n::::::: Set Credits :::::::\n");
credits = read_int_prompt("(credits) >");
}
void change_game(){
int opt = 0;
do{
opt = read_int_prompt("Select game: (1)Pick a Number or (2)No Match Dealer\n>");
} while(opt < 3 && opt > 0);
}
void administration() {
int opt = 0;
void (*fptr)() = admin_functionality[DEFAULT_GAME];
unsigned char correct_hash[20] = {
0x33, 0x54, 0xcd, 0xb5, 0x14, 0x69, 0xa8, 0xfa, 0x4f, 0x9a,
0x92, 0x53, 0xca, 0x62, 0x90, 0x56, 0xd7, 0xcd, 0xc1, 0x2f
};
unsigned char salt[8] = {0x6d, 0x62, 0x67, 0x59, 0x7a, 0x52, 0x72, 0x64};
unsigned char password[20] = {0};
unsigned char salted_password[28];
printf("This is admin functionality.\nPassword: ");
read_string(password, 54);
memcpy(salted_password, salt, 8);
memcpy(salted_password+8, password, 20);
SHA1(salted_password, strlen((char *)salted_password), password);
if (memcmp(password, correct_hash, 20) == 0){
do{
opt = read_int_prompt("Select functionality: (1) change game or (2) set credits\n>");
} while(opt > 2 && opt < 1);
if (opt-1 != DEFAULT_GAME){
fptr = admin_functionality[opt-1];
}
fptr();
} else {
printf("Authentication failed!\n");
}
}
void game_2() {
int i, j;
int numbers[16];
int set_credits = -1;
int match = -1;
printf("\n::::::: No Match Dealer :::::::\n");
printf("Wager up to all of your credits.\n");
printf("The dealer will deal out 16 random numbers between 0 and 99.\n");
printf("If there are no matches among them, you double your money! (stonks!)\n\n");
if (credits == 0) {
printf("You don't have any credits to wager!\n\n");
return;
}
set_credits = read_int_prompt("Wager credits. If you guess the number we roll, you get back the double amount otherwise you lose them\n> ");
if ((unsigned int)set_credits > credits) {
printf("You cannot set more credits than you own!\n");
} else {
credits = credits - set_credits;
}
printf("\t\t::: Dealing out 16 random numbers :::\n");
for (i=0; i < 16; i++) {
numbers[i] = rand() % 100; /* pick a number 0 to 99 */
printf("%2d\t", numbers[i]);
if (i%8 == 7) /* Print a line break every 8 numbers. */
printf("\n");
}
for (i=0; i < 15; i++) { /* Loop looking for matches */
j = i + 1;
while (j < 16) {
if (numbers[i] == numbers[j])
match = numbers[i];
j++;
}
}
if (match != -1) {
printf("The dealer matched the number %d!\n", match);
printf("You lose %d credits.\n", set_credits);
credits -= set_credits;
} else {
printf("There were no matches! You win %d credits!\n", set_credits);
credits += set_credits;
}
return;
}
void game_1() {
int set_credits;
int guess;
printf("\n::::::::::: Pick a Number :::::::::::\n");
if (credits == 0) {
printf("Thank you for playing. Unfortunately, you lost everything. Bye, see you the next time.\n");
return;
}
printf("Wager credits. If you guess the number we roll, you get back the double amount otherwise you lose them\n");
set_credits = read_int_prompt("Credits to wager: ");
if ((unsigned int)set_credits > credits) {
printf("You cannot set more credits than you own!\n");
} else {
credits = credits - set_credits;
}
guess = read_int_prompt("Guess a number between 1 and 12 to win the game:\n> ");
if ((rand() % 12) +1 == guess) {
printf("You won %d credits\n", set_credits * 2);
credits = credits + set_credits * 2;
} else {
printf("You lost %d credits\n", set_credits);
}
}
void play(){
int opt = 0;
while(1){
print_menu();
opt = read_int_prompt(">> ");
switch (opt) {
case 1:
games[current_game]();
break;
case 2:
administration();
break;
case 3:
puts("Pleasure doing business with you!");
exit(0);
break;
default:
puts("Invalid option");
}
}
}
int main(void) {
setvbuf(stdout, 0, 2, 0);
setvbuf(stderr, 0, 2, 0);
initialize_seed();
credits = 10;
play();
return 0;
}
我已经尝试为每个输入给程序大输入,以查看是否发生任何分段错误。但是,对于我发送的所有输入,程序只是正常退出。我想知道如何在 gdb 中找到容易受到缓冲区溢出攻击的变量?