这个程序的漏洞在哪里? (简单的缓冲区溢出)

问题描述 投票:0回答:0

我有一个程序,被告知要利用缓冲区溢出攻击。 据我所知,当我们将一个变量移动到另一个变量时,例如调用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 中找到容易受到缓冲区溢出攻击的变量?

security buffer-overflow
© www.soinside.com 2019 - 2024. All rights reserved.