英文:
Where is the vulnerability for this program? (simple buffer overflow)
问题
你好,以下是代码部分的翻译:
#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, 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
<details>
<summary>英文:</summary>
I have got a program and was told to exploit a buffer overflow attack.
From what I know, buffer overflow occurs when we do no bound check when we move a variable to another variable, such as calling function like gets, strcmp. However, I have spent a few days and still cant figure out where is the vulnerability in my program. Can someone give me some hints to start or how can I look for a variable that is vulnerable getting buffer overflow attack? Many thanks.
Below is the code:
#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;
}
I have tried giving the program large input for every input, to see if there is any segmentation fault occurs. However, for all of the input I send, the program just exit normally. I would like to know how can I find variable that is vulnerable for buffer overflow attack in gdb?
</details>
# 答案1
**得分**: 1
The buffer overflow is here:
read_string(password, 54);
`password` is only 20 bytes long. `read_string` is willing to write up to its second parameter's bytes.
Depending on your processor and compiler, this could allow you to overwrite `salt` and `correct_hash` with an over-long password.
<details>
<summary>英文:</summary>
The buffer overflow is here:
read_string(password, 54);
`password` is only 20 bytes long. `read_string` is willing to write up to its second parameter's bytes.
Depending on your processor and compiler, this could allow you to overwrite `salt` and `correct_hash` with an over-long password.
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论