This is a basic learning stuff to begin into buffer overflow exploitation. To simplify, all protection such as PIE will be deactivated.
Code source example
#include<stdio.h>#include<string.h>#include<stdlib.h>voidprintSecret(void) {printf("Good job !\n");}voidcheckPassword(char*password) {char passwd[16] =""; // array to store the password FILE *fp =fopen(".passwd","r");fread(passwd,1,15, fp);fclose(fp); passwd[15] ='\0';if (strcmp(password, passwd)==0) {printSecret(); } else {printf("Permission denied !\n"); }}voidgetPassword(void) {char password[16] ="";printf("Enter password: ");scanf("%s", password); // read the password from the usercheckPassword(password);}intmain() {getPassword();return0;}
#include<stdio.h>#include<string.h>#include<stdlib.h>voidprintSecret(void) {printf("Good job !\n");}voidcheckPassword(char*password) {char passwd[16] =""; // array to store the password FILE *fp =fopen(".passwd","r");fread(passwd,1,15, fp);fclose(fp); passwd[15] ='\0';if (strcmp(password, passwd)==0) {printSecret(); } else {printf("Permission denied !\n"); }}voidgetPassword(void) {char password[16] ="";printf("Enter password: ");scanf("%15s", password); // read the password from the usercheckPassword(password);}intmain() {getPassword();return0;}
Here the objectif is to exploit the buffer overflow in order to execute the printSecret function.
Exploitation
This program is vulnerable to Buffer Overflow. In this case, the password array has a size of 16 characters, but the program does not check the length of the input entered by the user. This means that if the user enters a password that is longer than 15 characters, it will overwrite adjacent memory locations.
Here, password is set alone into a specific function, so it's not possible to overwrite the passwd variable in order to match the if condition.
However, As explained in the "operation of the stack" part, at the call of the function the process store the value of the instruction pointer onto the stack. Thus, even though the password variable is the first declared variable into the stack frame, there is the saved instruction pointer under it.
Here the process take 0x18 bytes of marge. (0x0804926d <+3>: sub esp,0x18). remember that in the source code, the password variable is 16 byte long (0xf), so there is :
We insert 16 times 0x41 into password in order to make it easier to view it.
The address should be sent in little endian here. See Endianness
the exploit work because, when the process end the getPassword function, it will restore the instruction pointer with the value saved into the stack, but this value was overloaded with a controled value. Thus the instruction pointer now target an arbitrary address unless the expeted next instruction.
Exercice
If you want to try this exploit by yourself, you can pull this docker image :
docker pull thectfrecipes/pwn:eip_overwrite
Deploy the image using the followed command :
docker run --name buffer_overflow_eip_overwrite -it --rm -d -p 3000:3000 thectfrecipes/pwn:eip_overwrite
Access to the web shell with your browser at the address : http://localhost:3000/