I am working on a security engineering assignment where I need to create a buffer overflow exploit to change the execution flow of a C program. The goal is to overwrite the return address and redirect execution to a specific function (dump_users). However, I keep encountering a segmentation fault, and I need help to resolve this.
Program Details
Here’s the relevant part of my C program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define USERNAME_SIZE 32
#define PASSWORD_SIZE 16
#define FILENAME "users.txt"
typedef struct {
char username[USERNAME_SIZE];
char password[PASSWORD_SIZE];
} User;
void register_user() {
FILE *file = fopen(FILENAME, "a");
if (file == NULL) {
perror("Error opening file");
return;
}
User user;
printf("Enter username: ");
gets(user.username); // Vulnerable function
printf("Enter password: ");
gets(user.password); // Vulnerable function
fwrite(&user, sizeof(User), 1, file);
fclose(file);
printf("User registered successfully.\n");
}
void login() {
FILE *file = fopen(FILENAME, "r");
if (file == NULL) {
perror("Error opening file");
return;
}
char username[USERNAME_SIZE];
char password[PASSWORD_SIZE];
User user;
int authenticated = 0;
printf("Enter username: ");
gets(username);
printf("Enter password: ");
gets(password);
while (fread(&user, sizeof(User), 1, file)) {
if (strcmp(username, user.username) == 0 && strcmp(password, user.password) == 0) {
authenticated = 1;
break;
}
}
fclose(file);
if (authenticated) {
printf("Login successful!\n");
} else {
printf("Login failed!\n");
}
}
void dump_users() {
FILE *file = fopen(FILENAME, "r");
if (file == NULL) {
perror("Error opening file");
return;
}
User user;
printf("Registered users:\n");
while (fread(&user, sizeof(User), 1, file)) {
printf("Username: %s, Password: %s\n", user.username, user.password);
}
fclose(file);
}
int main() {
int choice;
while (1) {
printf("1. Register\n");
printf("2. Login\n");
printf("3. Dump users\n");
printf("4. Exit\n");
printf("Enter your choice: ");
scanf("%d", &choice);
switch (choice) {
case 1:
register_user();
break;
case 2:
login();
break;
case 3:
dump_users();
break;
case 4:
return 0;
default:
printf("Invalid choice.\n");
}
}
return 0;
}
I want to perform a buffer overflow attack by overwriting the return address to call the dump_users function when register_user returns.
Details from GDB Address of dump_users: 0x555555555718 Buffer overflow point: gets(user.username) Buffer size: 32 bytes Saved return address offset: 40 bytes from the start of the buffer (considering padding and saved rbp).
Compiled the program without stack protection and with ASLR disabled:
gcc -fno-stack-protector -o main main.c
sudo sh -c 'echo 0 > /proc/sys/kernel/randomize_va_space'
Created the payload:
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x18\x57\x55\x55\x55\x55\x00\x00
Input the payload manually during the register_user prompt:
Enter username: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x18\x57\x55\x55\x55\x55\x00\x00
Problem Despite following these steps, I still encounter a segmentation fault after the payload is executed. Here’s the GDB output:
Program received signal SIGSEGV, Segmentation fault.
0x00005555555553ba in register_user () at main.c:39
39 }
GDB Frame Information
(gdb) info frame
Stack level 0, frame at 0x7fffffffdad0:
rip = 0x55555555534c in register_user (main.c:32); saved rip = 0x55555555570f
called by frame at 0x7fffffffdb00
source language c.
Arglist at 0x7fffffffdac0, args:
Locals at 0x7fffffffdac0, Previous frame's sp is 0x7fffffffdad0
Saved registers:
rbp at 0x7fffffffdac0, rip at 0x7fffffffdac8
(gdb) x/20x $rsp
0x7fffffffdaa0: 0x00000000 0x00000000 0xffffdaf0 0x00007fff
0x7fffffffdab0: 0x00000000 0x00000000 0xffffdaf0 0x00007fff
0x7fffffffdac0: 0xffffdaf0 0x00007fff 0x5555570f 0x00005555
0x7fffffffdad0: 0xffffdc08 0x00007fff 0x00000000 0x00000001
0x7fffffffdae0: 0x00000000 0x00000000 0x00000000 0x00000001
Question How can I correctly craft the payload to overwrite the return address and redirect execution to the dump_users function? What am I missing in my current approach?
\x18are meant to be entered as single bytes. Did you check that they are? You should be able to see the buffer overflow and its values in the debugger.