ūü¶ĀNarnia 5

ūü¶ĀNarnia 5

1 June 2023 Narnia challenges 0

Nous sommes de retour avec le 6ème challenge de cette série !

Celui-ci va nous permettre de découvrir de nouvelles vulnérabilités, encore jamais vu dans les challenges Narnia : les formats strings !

Découverte

				
					#include 
#include 
#include  

int main(int argc, char **argv){
        int i = 1;
        char buffer[64];

        snprintf(buffer, sizeof buffer, argv[1]);
        buffer[sizeof (buffer) - 1] = 0;
        printf("Change i's value from 1 -> 500. ");

        if(i==500){
                printf("GOOD\n");
        setreuid(geteuid(),geteuid());
                system("/bin/sh");
        }

        printf("No way...let me give you a hint!\n");
        printf("buffer : [%s] (%d)\n", buffer, strlen(buffer));
        printf ("i = %d (%p)\n", i, &i);
        return 0;
}
				
			

Le but de ce challenge est d’obtenir un i = 500.

Gr√Ęce √† la sortie, on connait l‚Äôadresse m√©moire de i et la valeur du buffer (ainsi que sa longueur).

Ici la vulnérabilité va se situer au niveau du snprintf.

En effet il s’agit d’une fonction peu sécurisée car elle ne vérifie pas la taille du buffer de destination. 

De plus, elle permet √† un attaquant d’acc√©der ou de modifier des valeurs sur la pile gr√Ęce √† une attaque par injection de format.

Celle-ci s‚Äôexploite en envoyant des chaines de format tel que “%x”.

Pour rappel, les fonctions de la famille format on retrouve : 

– snprintf

–¬†sprintf

– printf

– fprintf

– vfprintf

– etc.

Ces fonctions prennent des paramètres qui spécifient un format (les format specifiers ou chaine de format). Voici quelques exemples : 

Exploitation

La fonction snprintf fonctionne de la manière suivante :

				
					snprintf(destination, taille à lire, source, options)
# Exemple
snprintf(buffer, 256, "Coucou%x", val)
				
			

Dans cet exemple, la chaine “Coucou” va √™tre copi√© dans le buffer.

De plus, la valeur de val sera affiché en hexadécimal.

Or, si nous ne précisons pas de variable à lire, snprintf va tout de même lire une valeur, celle de la pile.

Nous pouvons tester la vulnérabilité en essayant de visualiser la pile :

				
					/narnia/narnia5 $(python2 -c 'print("%08x.%08x.%08x.%08x\n")')
				
			

Résultat de la commande :

				
					Change i's value from 1 -> 500. No way...let me give you a hint!
buffer : [f7fc4500.30303534.3330332e.33353330] (35)
i = 1 (0xffffd520)

				
			

A l’int√©rieur de la variable buffer, on peut voir les 4 derni√®res valeurs pr√©sentes sur la pile !

Ce qui se passe ici : printf va interpr√©ter tous les format specifiers (%x) et lire l‚Äôadresse pr√©c√©dente de la pile.

Nous pouvons ainsi d√©duire que l’on peut manipuler les format specifiers afin de modifier la valeur de i.

Pour cela, nous allons avoir besoin du format specifier %n. J’ai mis du temps √† comprendre son fonctionnement et son utilit√©.

Pour des explications compl√®tes, je vous conseille ce guide : formatstring-1.2.pdf (stanford.edu).

Dans les grandes lignes, %n permet de compter le nombre d’octets √©crits jusqu’√† pr√©sent et de l’√©crire dans une variable en param√®tre. 

Il peut donc être utilisé pour écrire directement sur la pile.

En effet, lorsqu’on utilise %n comme ci-dessous, il permet d’√©crire le nombre de caract√®re √©crit dans la variable val :

				
					snprintf(buffer, 256, "Coucou%n", val)
				
			

Or dans notre exemple, il n’y a pas de param√®tre val :¬†

				
					snprintf(buffer, sizeof buffer, argv[1]);
				
			

Si notre chaine de caract√®re contient donc des “%n”, il √©crira dans la pile comme s’il y avait un param√®tre.¬†

Il y a notamment 2 méthodes à combiner afin de résoudre le challenge : la méthode du Direct Access Parameters et les exploitations de format strings classiques.

Exploitation de format strings classiques

Pour comprendre l’exploitation de format strings classique, ce guide m’a beaucoup aid√© :¬†Format Strings Exploitation Tutorial (exploit-db.com)

Il reprend des exemples d’exploitations basiques dont on peut s’inspirer pour notre exploit.

Par exemple :

				
					 $(printf "\x84\x95\x04\x08AAAA")%x%x%x%x%x%x%x%x%x%n
				
			

Cette injection permet d’√©crire √† l’adresse 0x08049584.

Le dernier %x a √©t√© remplac√© par un %n, ce qui permet d’√©crire le nombre d’octets jusqu’√† pr√©sent, dans l’adresse donn√©e.

Dans notre cas, nous n’avons pas besoin d’√©crire “AAAA” pour notre injection finale. Ces A ne sont l√† qu’√† des fins de test, pour les retrouver sur la pile.

On peut transposer cette injection en python, ce qui nous donne :

				
					$(python2 -c 'print("\x84\x95\x05\x08")')%x%x%x%x%x%x%x%x%x%n
				
			

Je me suis inspir√© de ce mod√®le afin de construire mon injection, √† la diff√©rence que j’ai utilis√© la m√©thode “Direct Access Parameters”.

Méthode : Direct Access Parameters

Selon le guide formatstring-1.2.pdf (stanford.edu), on peut utiliser une m√©thode de “stack popping” qui permet d’adresser directement un param√®tre de la pile (Direct Parameter Access).

Cela signifie placer directement un √©l√©ment sur la pile.

Cet acc√®s se fait par le qualificatif ‘$’.

En lisant le guide, on comprend que %1$n permet en fait d‚Äô√©crire √† un emplacement m√©moire le dernier argument entr√©.

En effet, le 1 indique le premier argument passé après la chaine de format.

Le $n est l’√©quivalent de %n. Il s’agit d’un sp√©cifieur de format, utilis√© pour √©crire l’argument pass√©, √† l’adresse sp√©cifi√©e auparavant. 

Nous avons aussi besoin d’un emplacement m√©moire et d’une donn√©e √† √©crire sur la pile.

Ainsi, on se retrouve avec une injection de ce format là :

				
					$(python2 -c 'print("adresse")')%Nx%1\$n
				
			

O√Ļ N est un chiffre hexad√©cimal (x) (l’argument) √† √©crire √† l’adresse “<adresse>"

Conclusion

J’ai trouv√© ce challenge tr√®s int√©ressant, il se penche sur un nouveau type de vuln√©rabilit√©s, encore jamais abord√© au cours de ce wargame.

Il existe de nombreuses façon différentes de résoudre ce challenge.

Il m’a sembl√© mystique au d√©but, complexe √† prendre en main, mais gr√Ęce √† de nombreuses documentations et guides, il est possible d’en venir √† bout ūüėä.

Ressources