Un regard sur l'exploitation des vulnérabilités

Comme j'avais hâte de continuer à discuter de ce sujet, laissez-moi vous raconter un peu d'histoire, de théorie et de pratique sur les vulnérabilités. Nous savons tous que les failles de sécurité peuvent coûter cher, nous savons tous que nous devons garder nos logiciels à jour, nous savons tous que de nombreuses mises à jour sont causées par des bogues de sécurité. Mais aujourd'hui je vais vous dire un peu comment ces erreurs sont trouvées et exploitées 🙂 Mais avant cela nous allons clarifier quelques détails afin d'avoir une meilleure vue d'ensemble.

Avant de commencer

Je veux d'abord vous dire que nous allons nous concentrer sur la première vulnérabilité que j'ai appris à exploiter, la Débordements de tampon, dans cette vulnérabilité on profite d'un manque de vérification de la mémoire pour faire des choses amusantes 🙂 Mais clarifions un peu plus à ce sujet.

Ce ne sera pas un scénario du monde réel

Je ne peux pas me permettre de leur apprendre à casser n'importe quel programme qu'ils voient - d'abord parce que c'est dangereux pour leurs ordinateurs, ensuite parce que cela prendrait plus que mon quota habituel de mots.

Nous partons en voyage dans les années 80

Ce que je vais vous montrer que je peux faire sur mon ordinateur portable, mais cela ne veut pas dire que cela peut être fait aujourd'hui de manière simple 🙂 beaucoup de ces concepts ont déjà été exploités tellement de fois que de nouvelles méthodes de protection et de nouvelles méthodes pour y échapper sont apparues 😛 mais ça nous ramène au même endroit, il n'y a pas d'espace pour pouvoir dire tout ça 🙂

Cela peut ne pas fonctionner sur votre processeur

Bien que je vais utiliser un exemple très simple, je veux qu'il soit tout à fait clair dès le début que les détails de celui-ci sont si nombreux et si variés que, tout comme cela peut être le même que moi, si vous voulez l'essayer, l'effet souhaité peut également ne pas être obtenu 🙂 Mais vous pouvez imaginer que je ne peux pas expliquer cela dans cet espace, d'autant plus qu'avec cette introduction j'ai déjà pris plus de 300 mots, nous allons donc droit à notre propos.

Qu'est-ce qu'un Débordement de tampon

Pour répondre à cela, nous devons d'abord comprendre la première moitié de cette combinaison.

Buffers

Comme tout est question de mémoire dans un ordinateur, il est logique qu'il y ait un type de conteneur d'informations. Quand on parle de entrées sorties, nous arrivons directement au concept de tampons. Pour faire court, un tampon C'est un espace mémoire de taille définie dans lequel on va stocker une quantité d'informations, simple 🙂

Les débordements se produisent, comme son nom l'indique, lorsqu'un tampon se remplit de plus d'informations qu'il ne peut en gérer. mais pourquoi est-ce important?

Stack

Également appelés piles, il s'agit d'un type de données abstrait dans lequel nous pouvons empiler informations, leur principale caractéristique est d'avoir une commande LIFO (dernier entré, premier sorti). Pensons une seconde à une pile d'assiettes, on les place sur le dessus une par une, puis on les sort une à une du haut, cela fait que la dernière assiette que nous avons mise (celle qui est en haut) est la première assiette que nous allons sortir, évidemment si nous ne pouvons sortir qu'une seule plaque à la fois et que nous décidons de le faire dans cet ordre: P.

Maintenant que vous connaissez ces deux concepts, nous devons les mettre en ordre. Les piles sont importantes car chaque programme que nous exécutons a son propre pile d'exécution. Mais cette pile a un caractéristique particulièregrandit. La seule chose que vous devez savoir à ce sujet est que lorsqu'un programme est en cours d'exécution, lorsqu'une fonction est appelée, la pile passe d'un nombre X en mémoire à un nombre (Xn). Mais pour continuer, nous devons comprendre un autre concept.

Pointeurs

C'est un concept qui rend fous de nombreux programmeurs lorsqu'ils débutent dans le monde du C, en fait la grande puissance de la programmation C est due en partie à l'utilisation de pointeurs. Pour faire simple, un pointeur pointe vers une adresse mémoire. Cela semble complexe, mais ce n'est pas si complexe, nous avons tous de la RAM dans nos machines, non? Eh bien, cela peut être défini comme un disposition consécutive de blocs, ces emplacements sont normalement exprimés en nombres hexadécimaux (de 0 à 9 puis de A à F, tels que 0x0, 0x1, 0x6, 0xA, 0xF, 0x10). Ici comme une note curieuse, 0x10 NON est égal à 10 😛 si nous le convertissons en ordre décimal, ce serait la même chose que de dire 15. C'est quelque chose qui en confond aussi plus d'un au début, mais allons-y.

Archives

Les processeurs fonctionnent avec un certain nombre de archives, qui travaillent pour transmettre des emplacements de la mémoire physique au processeur, pour les architectures utilisant 64 bits, le nombre de registres est important et difficile à décrire ici, mais pour se faire une idée, les registres sont comme des pointeurs, ils indiquent entre autres choses, un espace mémoire (emplacement).

Maintenant, pratiquez

Je sais que cela a été beaucoup d'informations à traiter jusqu'à présent, mais en réalité ce sont des problèmes un peu complexes que j'essaie d'expliquer de manière très simple, nous allons voir un petit programme qui utilise des tampons et nous allons le casser pour comprendre cela à propos des débordements, évidemment celui-ci n'est pas C'est un vrai programme, et nous allons «échapper» à bon nombre des contre-mesures qui sont utilisées aujourd'hui, juste pour montrer comment les choses étaient faites avant 🙂 et parce que certains de ces principes sont nécessaires pour pouvoir apprendre des choses plus complexes 😉

GDB

Un excellent programme qui est sans aucun doute l'un des plus utilisés par les programmeurs C. Parmi ses nombreuses vertus, nous avons le fait qu'il nous permet de voir tout ce dont nous avons parlé jusqu'à présent, les registres, la pile, les buffers, etc. 🙂 Voyons voir le programme que nous allons utiliser pour notre exemple.

retinput.c

Posséder. Christopher Diaz Riveros

C'est un programme assez simple, nous allons utiliser la bibliothèque stdio.h pour pouvoir obtenir des informations et les afficher dans un terminal. Nous pouvons voir une fonction appelée return_input qui génère un tampon appelé tableau, qui a une longueur de 30 octets (le type de données char est de 1 octet).

La fonction gets(array); demander des informations par console et fonction printf() renvoie le contenu du tableau et l'affiche à l'écran.

Tout programme écrit en C commence par la fonction main(), ce sera uniquement en charge d'appeler return_input, maintenant nous allons compiler le programme.

Posséder. Christopher Diaz Riveros

Prenons un peu ce que je viens de faire. L'option -ggdb dit à gcc de compiler le programme avec des informations pour que gdb puisse correctement déboguer. -fno-stack-protector C'est une option que nous ne devrions évidemment pas utiliser, mais que nous allons utiliser car sinon il serait possible de générer le buffer overflow dans la pile. En fin de compte, j'ai testé le résultat. ./a.out il exécute juste ce que je viens de compiler, il me demande des informations et les renvoie. Courir 🙂

Avertissements

Une autre note ici. Pouvez-vous voir les avertissements? clairement c'est quelque chose à prendre en compte quand on travaille avec du code ou que l'on compile, c'est un peu évident et il y a peu de programmes qui aujourd'hui ont la fonction gets() Dans le code. Un avantage de Gentoo est qu'en compilant chaque programme, je peux voir ce qui pourrait être faux, un programme "idéal" ne devrait pas les avoir, mais vous seriez surpris de voir combien de grands programmes ont ces avertissements car ils sont juste TRÈS gros et il est difficile de les suivre. fonctions dangereuses lorsqu'il y a plusieurs avertissements en même temps. Maintenant si nous continuons

Débogage du programme

Posséder. Christopher Diaz Riveros

Maintenant, cette partie peut être un peu déroutante, mais comme j'ai déjà écrit pas mal, je ne peux pas me permettre de tout expliquer, alors désolé si vous voyez que je vais trop vite 🙂

Désarmer le code

Commençons par regarder notre programme compilé en langage machine.

Posséder. Christopher Diaz Riveros

C'est le code de notre fonction principale dans Assemblée, c'est ce que comprend notre processeur, la ligne de gauche est l'adresse physique en mémoire, le <+ n> il est connu comme compenser, essentiellement la distance entre le début de la fonction (main) et cette instruction (appelée code opération). Ensuite, nous voyons le type d'instruction (push / mov / callq…) et un ou plusieurs registres. En résumé, nous pouvons dire que c'est l'indication suivie de la source / origine et de la destination. <return_input> fait référence à notre deuxième fonction, jetons un œil.

Entrée_retour

Posséder. Christopher Diaz Riveros

C'est un peu plus complexe, mais je veux juste que vous vérifiiez quelques choses, il y a une balise appelée <gets@plt> et un dernier opcode appelé retq indiquant la fin de la fonction. Nous allons mettre quelques points d'arrêt, un dans la fonction gets et un autre dans le retq.

Posséder. Christopher Diaz Riveros

Courir

Nous allons maintenant exécuter le programme pour voir comment l'action commence.

Posséder. Christopher Diaz Riveros

On peut voir qu'une petite flèche apparaît indiquant l'opcode où nous sommes, je veux qu'ils prennent en compte la direction 0x000055555555469b, c'est l'adresse après l'appel à return_input en fonction main , ceci est important car c'est là que le programme doit revenir lorsque vous avez fini de recevoir le contribution, entrons dans la fonction. Maintenant nous allons vérifier la mémoire avant d'entrer dans la fonction gets.

Posséder. Christopher Diaz Riveros

J'ai rétabli la fonction principale pour vous et j'ai mis en évidence le code auquel je faisais référence, comme vous pouvez le voir, en raison du endianité a été séparé en deux segments, je veux qu'ils prennent en compte la direction 0x7fffffffdbf0 (le premier en partant de la gauche après le commando x/20x $rsp) puisque c'est l'emplacement que nous devons utiliser pour vérifier les résultats de gets, continuons:

Rompre le programme

Posséder. Christopher Diaz Riveros

J'ai mis en évidence ces 0x44444444parce qu'ils sont la représentation de nos D 🙂 maintenant nous avons commencé à ajouter contribution au programme, et comme vous pouvez le voir, nous ne sommes qu'à deux lignes de notre adresse souhaitée, nous allons la remplir jusqu'à ce que nous soyons juste avant les adresses que nous avons mises en évidence à l'étape précédente.

Changer le chemin de retour

Maintenant que nous avons réussi à entrer dans cette section du code où elle indique le retour de la fonction, voyons ce qui se passe si nous changeons l'adresse 🙂 au lieu d'aller à l'emplacement de l'opcode qui suit celui que nous avions il y a un instant, qu'en pensez-vous si nous retournons à return_input? Mais pour cela, il faut écrire l'adresse que l'on veut en binaire, on va le faire avec la fonction printf de bash

Posséder. Christopher Diaz Riveros

Maintenant, nous avons reçu les informations deux fois 😀 le programme n'était sûrement pas fait pour cela, mais nous avons réussi à casser le code et à lui faire répéter quelque chose qu'il n'était pas censé faire.

réflexions

Ce simple changement peut être considéré exploiter très basique 🙂 ​​il a réussi à briser le programme et à faire quelque chose que nous voulons qu'il fasse.

Ce n'est que la première étape d'une liste presque infinie de choses à voir et à ajouter, il existe des moyens d'ajouter plus de choses que de simplement répéter une commande, mais cette fois, j'ai beaucoup écrit et tout ce qui concerne codage shell c'est un sujet à écrire plus que des articles, des livres complets je dirais. Désolé si je n'ai pas pu approfondir un peu plus les sujets que j'aurais aimé, mais il y aura sûrement une chance 🙂 Salutations et merci d'être ici.


Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont marqués avec *

*

*

  1. Responsable des données: Miguel Ángel Gatón
  2. Finalité des données: Contrôle du SPAM, gestion des commentaires.
  3. Légitimation: votre consentement
  4. Communication des données: Les données ne seront pas communiquées à des tiers sauf obligation légale.
  5. Stockage des données: base de données hébergée par Occentus Networks (EU)
  6. Droits: à tout moment, vous pouvez limiter, récupérer et supprimer vos informations.

  1.   2p2 dit

    Soyez plus direct. Écrivez moins et concentrez-vous sur ce qui compte

    1.    ChrisADR dit

      Salut, merci pour le commentaire.

      A vrai dire, j'ai coupé une bonne partie des idées, mais il me semblait quand même que cela laissait le minimum pour que quelqu'un qui n'a pas de connaissances en programmation puisse se faire une idée.

      salutations

      1.    anonyme dit

        Le problème est que ceux qui n'ont pas de connaissances en programmation ne sauront rien parce que c'est trop complexe au départ, mais ceux qui savent programmer apprécient d'être plus directs.

        Je suppose que vous ne pouvez pas atteindre tout le monde, vous devez choisir, et dans ce cas, vous avez péché de vouloir couvrir beaucoup.

        Au fait, je vous le dis en critique constructive, j'adore ces sujets et j'aimerais que vous continuiez à écrire des articles, félicitations!

    2.    anonyme dit

      Je pense comme toi.

      1.    ChrisADR dit

        Merci beaucoup à tous les deux !! Il est certainement difficile de comprendre comment atteindre le public cible quand la vérité est que le nombre de personnes avec un niveau de programmation avancé qui lisent ces articles est faible (du moins cela peut être déduit sur la base des commentaires)

        J'ai certainement péché de vouloir simplifier quelque chose qui nécessite une large base de connaissances pour être compris. J'espère que vous comprenez que depuis que je commence tout juste à bloguer, je n'ai pas encore découvert le point exact où mes lecteurs savent et comprennent ce que je dis. Cela rendrait beaucoup plus facile de dire la vérité 🙂

        J'essaierai d'être plus court quand ça le mérite sans dépersonnaliser le format, car séparer la manière d'écrire du contenu est un peu plus compliqué qu'on pourrait l'imaginer, je les ai au moins assez liés, mais je suppose qu'au final je pourrai ajouter des lignes dans au lieu de couper le contenu.

        salutations

  2.   Mario dit

    Où pourriez-vous en savoir plus sur le sujet? Un livre recommandé?

    1.    ChrisADR dit

      L'exemple que j'ai obtenu du manuel du Shellcoder par Chris Anley, John Heasman, Felix Linder et Gerardo Richarte, mais pour faire la traduction 64 bits, j'ai dû en apprendre davantage sur mon architecture, le manuel du développeur Intel, les volumes 2 et 3 sont un source assez fiable pour cela. Il est également bon de lire la documentation GDB, qui vient avec la commande 'info gdb', Pour apprendre l'assemblage et le C il y a beaucoup de très bons livres, sauf que les livres d'assemblage sont un peu vieux donc il y a un vide à combler avec un autre documentation de type.

      Le shellcode lui-même n'est plus aussi efficace de nos jours pour diverses raisons, mais il est toujours intéressant d'apprendre de nouvelles techniques.

      J'espère que cela aide un peu 🙂 Salutations

  3.   Franz dit

    Bon article, vieux blog desdelinux a renaît à nouveau =)
    Quand vous dites que le shell distant n'est pas si efficace, vous voulez dire des contre-mesures conçues pour atténuer les attaques, ils appellent cela une sécurité offensive.
    Salutations et continuez comme ça

    1.    ChrisADR dit

      Merci beaucoup Franz 🙂 mots très gentils, en fait je voulais dire que le Shellcoding aujourd'hui est beaucoup plus complexe que ce que nous voyons ici. Nous avons l'ASLR (random memory location generator), le protecteur de pile, les différentes mesures et contre-mesures qui limitent le nombre d'opcodes pouvant être injectés dans un programme, et ce n'est que le début.

      Cordialement,

  4.   logiciels gratuits dit

    Bonjour, allez-vous faire une autre partie pour élargir le sujet? C'est intéressant

    1.    ChrisADR dit

      Bonjour, le sujet est certes assez intéressant, mais le niveau de complexité que nous prendrions deviendrait très élevé, impliquant probablement un grand nombre d'articles pour expliquer les différents prérequis pour comprendre l'autre. J'écrirai probablement à ce sujet, mais ce ne seront pas les articles suivants, je veux écrire quelques sujets avant de continuer avec celui-ci.

      Salutations et merci pour le partage

  5.   cactus dit

    Très bon che! Vous contribuez à de superbes articles! Une question, je commence ce truc de sécurité informatique en lisant un livre intitulé «Assurer la sécurité par des tests de stylet». Ce livre est-il recommandé? Comment proposez-vous que je commence à m'enquérir de ces problèmes?

    1.    ChrisADR dit

      Bonjour cactus, c'est tout un univers sur les vulnérabilités, et autres, à vrai dire cela dépend beaucoup de ce qui retient votre attention, et des besoins que vous avez, un responsable informatique n'a pas besoin de savoir la même chose qu'un stylo-testeur Ou un enquêteur de vulnérabilité, ou un analyste médico-légal, une équipe de reprise après sinistre possède un ensemble de compétences très différent. Évidemment, chacun d'eux nécessite un niveau de connaissances techniques différent, je vous recommande de commencer à découvrir exactement ce que vous aimez, de commencer à dévorer des livres, des articles et autres, et surtout, de pratiquer tout ce que vous lisez, même s'il est périmé , cela va faire une différence à la fin.
      Cordialement,

  6.   Eizen dit

    Salut.
    Merci beaucoup d'avoir expliqué ce sujet, ainsi que d'avoir commenté que pour plus d'informations, nous avons le "Manuel du Shellcoder". J'ai déjà une lecture en attente 😉