Mot-clé - code source

Fil des billets - Fil des commentaires

mercredi, novembre 7 2012

Petites astuces vite fait

Pour renouer avec les quelques billets express que j'ai déjà pu faire voici, en vrac, une poignée d'astuces (principalement python) qui pourraient être utiles.

Swiss Knife - Creative Common by "focusforaword" on Flickr

Python2 ou Python3 ? Les deux !

J'ai l'impression que tout le monde code en python2, malheureusement "Python 3.x is the present and future of the language" donc il va bien falloir y passer. Pour ma part j'étais réticent à passer à Python3 principalement à cause d'une unique différence print "toto" en python2 (que je trouvais très pratique) devient print("toto") en python3, or des "print" j'en colle à toutes les sauces dans mes scripts. L'habitude étant ce qu'elle est je me retrouvait toujours à coller un print "toto" quelque part dans mon code et je me disait "oh et puis zut" et je basculais en 100% python2. Aujourd'hui je partage avec vous une "astuce" que j'utilise à présent pour rendre mes scripts compatibles python2 ET python3 : je remplace les print par les fonctions du module standard logging.

import logging
logging.basicConfig(level = logging.DEBUG, format="%(message)s")

//équivalent de 
// print "toto" # en python2
// print("toto") # en python3
logging.debug("toto")

Autre avantage du module logging : ça gère directement les différents niveau de verbosité[1]. Entre logging.debug, logging.info, logging.warning, et leurs consoeurs vous trouverez forcément le niveau de log qui vous plait; ainsi il n'est plus besoin de commenter en masse les print entre votre version de "dev" et de "prod" ^^


Le C c'est bien, mais parfois il faut l'oublier

J'aime beaucoup le C, mais sur ce coup là ça m'a joué un mauvais tour : quand j'ai voulu parser les arguments de la ligne de commande de mes scripts python je me suis intéressé au module getopt qui ressemble furieusement à ce qui existe en C. Erreur grossière : j'aurai mieux fait de regarder argparse qui est beaucoup plus pythonique et infiniment plus pratique ! A titre de comparaison voilà un exemple typique avec les deux modules. Les arguments possibles sont -h/- -help pour afficher l'aide, ou -v/- -verbose suivi d'un niveau de 0 à 4 pour régler la verbosité du programme. Voilà deux équivalents fonctionnels, l'un avec argparse, l'autre avec getopt :

import argparse, logging

parser = argparse.ArgumentParser(description='Super script de la mort qui tue')
parser.add_argument('--verbose', '-v', type=int, dest='verb', help='verbosity level [0-4]', default=4, choices=[0,1,2,3,4])
args = parser.parse_args()

logging.basicConfig(level = logging.CRITICAL-args.verb*10, format="%(message)s")
logging.debug("Debug") # cette ligne et les 2 suivante servent juste a voir que le setting du niveau de verbose fonctionne
logging.info("Info")
logging.warning("Warning")

Contre :

def usage():
    print "La on a un souci puisqu'on doit utiliser 'print'..."
    print "Et puis surtout on doit ecrire son 'usage' soit-meme alors qu'argparse l'ecrit automatiquement"
    print "Usage : %s [--verbose/-v LEVEL]"%sys.argv[0]
    print " --verbose/-v LEVEL\tVerbosity level between 0-5 [default to 4]" 

import sys, getopt, logging
try:
    opts, args = getopt.getopt(sys.argv[1:], "v:h", ["verbose", "help"])
except getopt.GetoptError, err:
        print str(err) # will print something like "option -a not recognized"
        usage()
        sys.exit(2)

verbose = 4
for o, a in opts:
    if o in ["-v","--verbose"]:
        try:
            verbose = int(a)
        except:
            usage()
            sys.exit(2)
        if not verbose in [0,1,2,3,4]:
            usage()
            sys.exit(2)
    elif o in ['-h', '--help']:
        usage()
        sys.exit(0)

logging.basicConfig(level = logging.CRITICAL-verbose*10, format="%(message)s")
logging.debug("Debug") # cette ligne et les 2 suivante servent juste a voir que le setting du niveau de verbose fonctionne
logging.info("Info")
logging.warning("Warning")

L'avantage d'argparse est évident pour tout le monde j'espère ! Par contre, bien qu'argparse soit censé être un module standard depuis python2.7, et qu'il soit par défaut présent sur ma ubuntu 12.04, j'ai été obligé de l'installer explicitement sur ma gentoo emerge dev-python/argparse...dommage.

Note

[1] Même si ce mot n'existe pas

dimanche, juillet 8 2012

Packons (ou pas) avec miasm et elfesteem

Comme beaucoup le savent à présent MIASM est un framework d'ingénierie inverse écrit en Python par Fabrice Desclaux. Pour ma part j'avais joué un petit peu avec il y a un an, mais j'étais finalement assez rapidement passé à autre chose devant mon incapacité à porter un "packeur" maison de pefile jusqu'à miasm. Aujourd'hui, je re-tente la même tâche !

Engine - Creative Common by "cbowns" on Flickr
Il y a un an donc j'avais eu des soucis quand j'avais voulu porter un concept simple de packeur sur le framework miasm. En effet la base de tout packeur c'est d'ouvrir un fichier à traiter (dans mon cas un fichier PE), lui apporter des modifications, puis le sauvegarder pour obtenir un clone fonctionnel de notre fichier à traiter (clone dont la signature binaire sera pourtant différente). Le problème c'est que, même en n'apportant aucune modification à mon fichier cible, elfesteem semblait incapable de générer un clone fonctionnel. Par exemple le code suivant, qui est censé n'apporter aucune modification à l'exécutable passé en argument, me retournait systématiquement un clone que Windows refusait de démarrer :

import sys
from elfesteem.pe_init import PE

e = PE( open(sys.argv[1]).read() )

open( sys.argv[1]+'_modified.exe', 'wb').write(str(e))

De mémoire j'avais testé sur "winmine.exe", sur "calc.exe", et sur "notepad.exe" : à chaque fois l'exécutable modifié ne fonctionnait plus :-(

Un an après, re-motivé par la super conf de serpi au SSTIC, je réinstalle smiasm sur ma machine[1] et je re-tente. Tristesse : le bilan est le même. Les exécutables que j'ouvre puis que je sauvegarde avec elfesteem ne fonctionnent plus (enfin en tout cas "calc.exe", qui est ma cible de test préférée, donne systématiquement des clones "cassés"). Mais cette année, j'ai décidé d'investiguer un petit peu plus ! Retroussons nous les manches et voyons voir ça de plus près. D'abord assurons nous que "calc.exe" et "calc.exe_modified.exe" sont bien différents (et que nous n'avons donc pas à faire à un simple saute d'humeur de windows) : diff calc.exe calc.exe_modified.exe nous confirme que les fichiers sont différents.

Pour y voir de plus près on va regarder ces deux spécimens en hexa (xxd calc.exe > calc.exe.XXD && xxd calc.exe_modified.exe > calc.modified.XXD && diff *.XXD) :

5,14c5,14
< 0000040: 0e1f ba0e 00b4 09cd 21b8 014c cd21 5468  ........!..L.!Th
< 0000050: 6973 2070 726f 6772 616d 2063 616e 6e6f  is program canno
< 0000060: 7420 6265 2072 756e 2069 6e20 444f 5320  t be run in DOS 
< 0000070: 6d6f 6465 2e0d 0d0a 2400 0000 0000 0000  mode....$.......
< 0000080: 8745 1664 c324 7837 c324 7837 c324 7837  .E.d.$x7.$x7.$x7
< 0000090: 3907 3837 c624 7837 1907 6437 c824 7837  9.87.$x7..d7.$x7
< 00000a0: c324 7837 c224 7837 c324 7937 4424 7837  .$x7.$x7.$y7D$x7
< 00000b0: 3907 6137 ce24 7837 5407 3d37 c224 7837  9.a7.$x7T.=7.$x7
< 00000c0: 1907 6537 df24 7837 3907 4537 c224 7837  ..e7.$x79.E7.$x7
< 00000d0: 5269 6368 c324 7837 0000 0000 0000 0000  Rich.$x7........
---
> 0000040: 0000 0000 0000 0000 0000 0000 0000 0000  ................
> 0000050: 0000 0000 0000 0000 0000 0000 0000 0000  ................
> 0000060: 0000 0000 0000 0000 0000 0000 0000 0000  ................
> 0000070: 0000 0000 0000 0000 0000 0000 0000 0000  ................
> 0000080: 0000 0000 0000 0000 0000 0000 0000 0000  ................
> 0000090: 0000 0000 0000 0000 0000 0000 0000 0000  ................
> 00000a0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
> 00000b0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
> 00000c0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
> 00000d0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
21c21
< 0000140: 00f0 0100 0004 0000 fcd7 0100 0200 0080  ................
---
> 0000140: 00f0 0100 0004 0000 b16f 0200 0200 0080  .........o......
39,46c39,46
< 0000260: 0ffe 7d3b 3800 0000 0efe 7d3b 4400 0000  ..};8.....};D...
< 0000270: 0efe 7d3b 4f00 0000 0efe 7d3b 5c00 0000  ..};O.....};\...
< 0000280: 0efe 7d3b 6900 0000 0efe 7d3b 7300 0000  ..};i.....};s...
< 0000290: 0000 0000 0000 0000 5348 454c 4c33 322e  ........SHELL32.
< 00002a0: 646c 6c00 6d73 7663 7274 2e64 6c6c 0041  dll.msvcrt.dll.A
< 00002b0: 4456 4150 4933 322e 646c 6c00 4b45 524e  DVAPI32.dll.KERN
< 00002c0: 454c 3332 2e64 6c6c 0047 4449 3332 2e64  EL32.dll.GDI32.d
< 00002d0: 6c6c 0055 5345 5233 322e 646c 6c00 0000  ll.USER32.dll...
---
> 0000260: 0000 0000 0000 0000 0000 0000 0000 0000  ................
> 0000270: 0000 0000 0000 0000 0000 0000 0000 0000  ................
> 0000280: 0000 0000 0000 0000 0000 0000 0000 0000  ................
> 0000290: 0000 0000 0000 0000 0000 0000 0000 0000  ................
> 00002a0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
> 00002b0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
> 00002c0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
> 00002d0: 0000 0000 0000 0000 0000 0000 0000 0000  ................

Voilà donc l'intégralité des changements entre les deux fichiers. Sur 112ko ça fait peu, on devrait pouvoir être capable d'identifier précisément ce qui ne fonctionne plus :)

Le premier bloc de différence se situe entre les octets 0x0000040 et 0x00000d0. La position (en tout début de fichier) et le contenu ("...This program cannot be run in DOS mode...") de ce bloc me font penser qu'il s'agit uniquement du "DOS stub"[2]. Bref : pas intéressant.

Le second bloc de différence est beaucoup plus petit puisqu'il n'impacte que la ligne de notre dump commençant à l'octet 0x0000140. Sur toute cette ligne on a 3 octets de différence. Si jamais ces octets participent à une indirection quelconque on a peut-être trouvé notre coupable :) ! Après un petit tour dans "Lord PE" je réalise que, malheureusement, ce n'est probablement pas là que se situe le coupable. En effet la valeur du checksum de "calc.exe" est "0001D7FC" et celle de "calc.exe_modified.exe" est de "00026FB1". Cette suite d'octets correspond donc probablement au checksum du fichier contenu dans l'en-tête NT_HEADER. Comme le DOS-stub a été supprimé il est normal que la valeur de checksum soit différente; de plus il me semble qu'un checksum erroné n'empèche pas le lancement de programme simples (pour les drivers c'est une autre histoire, mais pour un soft user-land je ne crois pas que Windows vérifie). Pour avoir la conscience tranquille je modifie quand même la valeur du checksum dans "calc.exe.XXD" puis je reconstruit un binaire (xxd -r calc.exe.XXD > calc.exe.badchecksum.exe) et je peux confirmer que cette copie de calc.exe dont j'ai uniquement modifié le checksum pour en mettre un invalide fonctionne :)

Nous arrivons ainsi au troisième bloc, qui est devenu notre suspect numéro 1. En plus, les quelques chaines de caractères qui ont été remplacées par des octets nuls ont bien la tête d'informations provenant d'une table d'importation ("msvcrt.dll" , "KERNEL3.dll", etc.) ce qui pourrait expliquer le non-fonctionnement du programme si ces informations ont été altérées. Malheureusemnt "Lord PE" me donne des tables d'importations identiques entre les deux fichiers "calc.exe" et "calc.exe_modified.exe", et je ne trouve pas d'outil sympa pour disséquer simplement un PE :-( ...Qu'à celà ne tienne : on va en pondre un maison, à la porc bien entendu ! L'idée est simple : visualiser les structures du fichier PE simplement afin d'identifier à quelle structure appartient la zone d'octets modifiés.

Pour réaliser cet outil, quick&dirty rappelons-le, je vais faire appel à une poignée de fidèles compagnons :

  • VIM/gedit : parce que ce sont d'excellents éditeurs de code :)
  • C : parce que pour les manipulation "bas niveau" on n'a pas encore fait mieux que le bon vieux C.
  • Python : parce que pour les prototypages rapide c'est le must.
  • Python Imaging Library (PIL) : parce qu'on veut "visualiser les structures du fichier PE" et que c'est la meilleure librairie de manipulation d'image en python que je connaisse.

Enfin, en guise d'aide mémoire, on utilisera aussi les excellents tutos d'Iczelions sur les entrailles du format PE et quelques URL de références de chez Krosoft. Au final j'ai obtenu en un aprem de jeu :

  • un prog en C qui analyse un fichier PE et dump ses caractéristiques sur la sortie standard (en prime j'ai rajouté un .h contenant les définitions des structures Windows, bien que j'aurai pu utiliser winnt.h qui doit se trouver quelque part sur ma machine étant donné que j'ai une gentoo avec de quoi compiler pour des centaines de systèmes exotiques, mais j'avais la flemme de le chercher :-D)
  • un prog en python qui lance le prog en C sur un exécutable passé en argument, parse la sortie obtenue, et génère deux jolies images permettant de visualiser quelle partie du fichier appartient à quelle structure.

Toutes les sources sont en pièce-jointe de ce billet, donc n'hésitez pas à jouez vous aussi (mais n'oubliez pas : j'ai codé ça comme un goret donc si ça ne marche pas chez vous "c'est normal", et si vous le lancez sur des PE de plusieurs Mo il est probable que votre RAM soit intégralement vampirisée, vous êtes prévenus).

La première image est une représentation à l'échelle des différentes structures du fichier PE sur disque (pas tel qu'il sera mappé en mémoire donc). La seconde image n'est qu'une représentation "compressée" de l'image précédente où j'ai inséré des séries de "petits points" pour remplacer visuellement les énormes applats de couleurs unis représentant des zones de fichier où "rien de spécial ne se passe" et qui rendent le premier type d'image carrément gigantesque (1200x14688 pour représenter "calc.exe" dans mon environnement de test ;) ). Voilà comment on s'en sert :

$ gcc -o a.out oz_pedissector.c
$ python oz_pedissector3.py calc.exe
INFO:root:PE zone discovered [ZONE : IMAGE_DOS_HEADER	En-tete DOS	0	64]
INFO:root:PE zone discovered [ZONE : IMAGE_NT_HEADERS	En-tete NT	240	488]
INFO:root:PE zone discovered [ZONE : SECTION_HEADERS[0]	En tete de section ".text"	488	528]
INFO:root:PE zone discovered [ZONE : SECTION[0]	Contenu de section ".text"	1024	76800]
(...)
INFO:root:Compression second pass 98%
INFO:root:Compression second pass 99%
INFO:root:Compression second pass finished.

Nous voilà à présent avec deux fichiers ".png", l'un étant la représentation à l'échelle, l'autre étant la représentation compressée. Voyons voir ce que donne l'image "compressée" générée automatiquement à partir du "calc.exe" de mon environnement de test (je vous invite à l'avoir sous les yeux en taille normale lorsque vous lirez le paragraphe suivant) :

Oz PE dissector (Compressed Example file) - Creative Common CC-BY-SA by Ozwald

En la regardant de haut en bas on retrouve bien :

  • L'en-tête MS-DOS commençant à l'adresse 0x0 et allant jusqu'à 0x40
  • Une zone noire (représentation graphique de "on ne sait pas ce que c'est") juste en dessous. C'est le DOS Stub.
  • l'en-tête NT commençant à 0xF0 et allant jusqu'à 0x1E8 (on se rappelle à ce moment là que le second bloc de différence était situé aux alentours de l'adresse 0x140 et que nous avions supposé qu'il s'agissait du checksum contenu dans l'en-tête NT, nous avons à présent confirmation que cette adresse est bien dans l'en-tête NT ce qui conforte notre hypothèse s'il en était besoin)
  • Les trois en-têtes de sections qui suivent l'en-tête NT
  • Une seconde zone noir juste en dessous...on en reparlera.
  • La première section (".text") qui va de 0x400 à 0x12C0. On notera (sur la droite de l'image) que cette section contient les zones mémoires suivantes appartenant au DATA_DIRECTORY : Import Address Table, Debug, Import Symbols.
  • La seconde section (".data") qui ne contient rien de spécial.
  • La troisième section (".rsrc") qui contient, on s'en doutai, la zone spéciale "Resources" du DATA_DIRECTORY.

Bref : tout va bien :) Tout va tellement bien d'ailleurs que je tombe d'accord avec elfesteem : il ne devrait rien y avoir d'important entre l'adresse 0x260 et 0x400[3]...Le mystère reste donc entier[4].

Edit du lundi 9 Juillet 2012, 14h53 : je remplace les 3 fichiers sources joints au billet par une archive unique contenant le tout, ça évitera les 403 imposés par mon hébergeurs sur les fichiers d'extension ".py" -_-

Edit du mardi 10 Juillet 2012, 17h30 : après vérification sur d'autres versions de "calc.exe" (provenant de diverses versions de WinXP) on retrouve toujours ce bloc non nul entre la fin des en-tête de section et le début de la première section... Etrange... Par contre je viens seulement maintenant de vérifier un exécutable qui serait plus typiquement ce que j'aurai besoin de packer[5], à savoir gsecdump, et il ne contient bien que des octets nuls entre la fin de ses en-tête de section et le début de sa première section. Donc à priori il devrait pouvoir être ouvert/enregistré par elfesteem sans être "cassé". Je teste ce soir :) ! Accessoirement je rajoute en PJ la version 4 du script dégueu programme permettant la visualisation des structures de fichiers PE. Il est maintenant infiniment moins gourmand en mémoire (forcément: il génère du svg directement compressé au lieu de générer un bitmap "taille réelle" puis de le compresser...); je l'ai testé sans douleur sur un binaire de 13Mo (en lui demandant cependant de n'afficher que les structures de plus de 40 octets).

Edit du mardi 10 Juillet 2012, 20h30 : A force d'avoir l'évidence sous les yeux (à savoir que je ne vois aucune raison pour lesquelles elfesteem ne pourrait pas légitimement écrire des bytes nuls sur ces zones du fichier) j'ai re-testé l'ouverture/sauvegarde simple mais sur plusieurs binaires ne provenant pas de Microsoft cette fois (à savoir : gsecdump-v2b5.exe, ftpserv.exe, notepad++.exe, 7zFM.exe, python.exe) et ils ont tous fonctionné à merveille après leur passage dans elfesteem. La conclusion du premier chapitre de ce mystère s'écrit donc d'elle même : elfesteem fonctionne très bien, c'est le compilateur utilisé par microsoft qui produit des résultats "exotiques" (et je suis un gros c*uillon de ne pas m'en être rendu compte il y a un an -_- ...).

Edit du mercredi 11 Juillet 2012 : Serpi a trouvé la solution (lisez les commentaires du billet pour les détails). Le problème venait de bound imports..

Notes

[1] L'installation n'est d'ailleurs toujours pas plus facile, je vous recommande la lecture de mon billet de l'époque, ça peut éventuellement aider

[2] Le DOS stub est,en résumé, un programme MSDOS censé être lancé à la place du programme PE lorsqu'il est exécuté sous DOS. Le but de ce mini programme DOS est principalement d'avertir l'utilisateur que le programme ne peut pas fonctionner sous DOS.C'est une zone totalement facultative de nos jours.

[3] Ce genre de zone "poubelle" pouvant apparaitre naturellement dans le fichier suite à des jeux de padding puisque les structures PE imposent des tailles multiples de certaines constantes renseignées dans les en-tête

[4] En attendant un autre après-midi de libre (où je pourrait me re-pencher sur le problème), ou que quelqu'un poste un commentaire expliquant ce bien étrange phénomène

[5] Pour rappel : je suis pentesteur pro, si je pack des binaires c'est pour mon taff et pour sensibiliser mes clients au fait qu'un AV ce n'est pas l'outil miracle qui les protègera de tout et n'importe quoi; ce n'est pas pour faire du pr0n, monter un botnet, ou pire : boire dans votre YOP.

dimanche, mai 13 2012

Culture automatisée

Ce qu'il y a de bien avec l'état d'esprit du "hack" c'est qu'on peut l'employer dans de nombreux domaines. Et ce qu'il y a de très bien c'est qu'on peut faire des combinaisons de plusieurs domaines ! Par exemple on peut faire un combo programmation/électronique/biologie et obtenir des petites expériences amusantes comme celle que je vais retranscrire ici.

Creative Common by Ozwald from ozwald.fr
L'idée de départ c'est qu'habitant en ville je ne peux planter aucun végétal "naturellement". A la rigueur je dispose de deux rebords de fenêtre pour poser des petits pots ou des jardinières mais c'est quand même super limité. Du coup comment faire pour améliorer autant que possible la pouse de jolies plantes carnivores ? La solution simple c'est d'abandonner la méthode "naturelle" (i.e. : fabriquer une tourbière de quelques mètres carrés avec écoulement d'eau permanent pour recréer des conditions marécageuses) et passer à de l'artificiel.

"Artificiel" ça peut recouper beaucoup de choses et du coup je me suis renseigné. J'ai ainsi découvert et approfondi les méthodes de cultures allant de la simple serre, à la culture aéroponique/ultraponique, en passant par l'hydroponique et l'aquaponique. Toutes ces méthodes semblent intéressantes mais il y a un point que j'ai trouvé systématiquement mal traité : l'éclairage. En effet on comprend vite que les méthodes en ultraponie, en hydroponie, ou en aquaponie, adressent principalement des problématiques d'arrosage; mais le problème de l'éclairage, lui, est souvent traité d'une façon qui m'a laissé sur ma faim. Bien souvent en effet les seuls remarques que l'on peut trouver sur l'éclairage se résument à quelque chose du genre : "une lampe au sodium super puissante, puisque c'est ce qui s'approche le plus de la vrai lumière du soleil et que ça chauffera super bien ta culture en placard où tu pourra planter plein d'herbe de provence[1]"

Ce genre de réponse ne me satisfait pas du tout puisqu'elle vise une problématique qui n'est pas la mienne. En effet ce type de réponse vise le problème de recréer des conditions naturelles dans un espace à l'abri des regards (à savoir un placard -_-); ma problématique à moi c'est de faire pousser des plantes carnivores (et des tomates cerises[2]). Ayant quelques bases en optique je me disais que les plantes n'avaient pas besoin de tout le spectre lumineux du soleil pour bien pousser, et du coup j'ai été faire un petit tour sur wikipédia pour obtenir le spectre d'absorbtion de la chlorophyle :

Spectre d'absorbtion de la chlorophyle - From Wikimedia

En regardant ça je me suis dit qu'il était probablement superflus de vouloir recréer un spectre lumineux continu, et je me suis dit qu'il était certainement énergétiquement plus intéressant de faire un éclairage par LED à des fréquences de couleur bien choisies :) ! J'ai farfouillé sur le net pour savoir si quelqu'un avait déjà fait ce genre d'expérience mais ce ne fut pas très fructueux. J'ai bien trouvé quelques personnes qui disaient qu'il fallait faire pousser sous du rouge, d'autre sous du rouge et du bleue, mais aucune référence sérieuse pour étayer le propos. Devant ce manque d'information pour me guider dans le choix (dois-je prendre des LED bleues ? Rouge ? Un mélange des deux ?) j'ai pris la décision le plus "simple" : faire un test[3].

Le protocole de test est simple : je vais réaliser en même temps 5 cultures de graines issus d'un même lot et semés dans un même terreau. L'une de ces cultures sera laissée à la lumière naturelle, l'une sera plongée dans le noir total, et les trois autres seront respectivement éclairés exclusivement par une diode rouge, bleue, et UV[4].

Pour cette expérience je vais donc utiliser 4 pots en plastique noir. L'un sera directement retourné sur la culture qui ne doit pas avoir de lumière, et les trois autres seront préparés pour éclairer au mieux d'une unique couleur les cultures qu'ils recouvreront. La préparation est simple : j'ai recouvert les bords intérieurs de papier aluminium afin que le maximum de lumière atteigne les plants, j'ai planté une diode sur le fond du pot pour que ses connections soient accessible de "l'extérieur", et j'ai calibré une résistance série pour que chaque diode consomme autant de puissance électrique malgré la différence de chute de tension à leur bornes : Pot opaque vu du dessus. Intérieur d'un pot pour éclairage mono-couleur.

Pour garder les diodes allumées 12h par jour, et éteintes 12h par jour j'avais deux solutions : les allumer moi-même à heure fixe tout les matins et les éteindre tout les soirs; ou opter pour une méthode de feignasse et utiliser un microcontrolleur pour qu'il fasse ça à ma place. Bien évidemment j'ai opté pour la solution micro-controlleur (ce qui m'a permit de m'entrainer à la gestion des timers et des interruptions, ainsi que de constater que si je veux faire une "vrai" horloge un jour il faudra que j'utilise un chip RTC pour compenser la dérive de l'oscillateur interne du micro-controlleur[5]). Si vous êtes curieux vous pouvez aller jeter un oeil au code que j'ai mis en pièce jointe de ce billet, m'enfin il n'est pas très intéressant puisque 70% du code porte sur l'affichage et le réglage de l'heure (affichage réalisé par un afficheur 7 segment, et réglé par un unique bouton permettant d'avancer le temps).

Il ne reste donc plus qu'à mettre le terreau dans un grand bac en plastique, à y semer des lentilles vertes (parce que, de mémoire de classe de CP, ça pousse super facilement et rapidement ces trucs là) et à lancer l'expérience. Voilà donc à quoi ressemble le montage expérimental : Expérience en place.

Après une dizaine de jours les résultats sont surprenants :) !

Pendant la germination nous avons deux cultures qui ont nettement pris la tête : la culture obscure (!!), et la culture rouge. Ces deux cultures étant suivi de prêt par les cultures bleue et UV, elles-même tallonnées par la culture au soleil.

Une fois la germination effectuée et les premières feuilles sorties on assiste à un équilibrage des 5 cultures en termes de longueur de pousse (y compris de l'obscure donc !). La seule culture qui se détache nettement des 4 autres reste néanmoins l'obscure puisqu'au lieu d'avoir de jolis plants verts elle a des plants blanchatre qui ont un peu de mal à tenir vertical.

Si vous voulez plus de détails sur le déroulement précis de la pousse de chaque échantillon vous pouvez télécharger le fichier ZIP joint à cet article, il contient quasiment une photo pour chaque jour d'expérience.

A partir de cette expérience super simpliste les questions ouvertes sont pourtant nombreuses :

  • Pourquoi le pot obscur germe-t-il aussi vite ? Est-ce grace à l'effet "serre" du pot opaque qui augmente l'humidité ?
  • J'ai visé du bleue, du rouge, et de l'UV, qui sont tout les trois normalement assez bien exploités par la chlorophyle; cependant le relatif "match nul" au bout de l'expérience me fait penser que j'aurai pu tenter une culture sous lumière verte pour vérifier si, comme la théorie l'indique, j'aurai obtenu les même résultats que dans l'obscurité (ou pas ?!)
  • Mes cultures sous lumière artificielle ont poussé quasiment à la même vitesse que celle exposée à la lumière du jour; que se passe-t-il si je double la puissance lumineuse artificielle ? Et si je la divise par deux ?
  • J'ai imposé des cycles jours/nuit de 12h/12h à mes cultures sous lumière artificielle. Que se passe-t-il si j'accélère ou si je ralenti ce cycle ?
  • Enfin une question évidente : que se passe-t-il sur une durée de vie plus longue de la plante (là j'ai abandonné l'expérience avant la maturation complète des lentilles faute de parvenir à bricoler des serres opaques assez grandes) ? De même que se passe-t-il sur d'autres plantes (par exemple sur les tomates cerises et les drosera/nepenthes que je vise) ?

Enfin, en guise de conclusion, je constaterait la chose suivante : Chaque LED utilisait environ 54mW de puissance électrique (51.5mW pour le rouge, 54.4mW pour le bleue, et 57.8mW pour l'UV), les pots faisant 7x7cm à la base (mesure intérieure) on est donc sur une consommation de 11W/m² pour l'éclairage, c'est à dire une énergie consommée de 48kWh pour un an d'éclairage. Si on recoupe avec les infos de Wikipédia sur les panneaux solaires (à savoir qu'un m² de panneau solaire a une puissance d'environ 150Watt Crete et qu'en Europe 1Watt Crete permet de produire environ 1kWh/an[6]) on obtient qu'un panneau solaire de 1m² pourrait, sur une année, fournir assez de puissance (150kWh) pour éclairer environ 3m² de culture :) Intéressant, non ?

Notes

[1] J'ai mis "herbe de provence" mais en réalité internet est submergé de conseils pour faire pousser un tout autre type de plante (dont, perso, la méthode de pousse m'intéresse encore moins que celle des herbes de provence).

[2] j'ai été obligé par ma copine

[3] On peut également dire "expérience" pour faire plus scientifique.

[4] Référez-vous à la courbe d'absorbtion de la chlorophyle, vos verrez que le rouge vise un pic important sur la chlorophyle A, la bleue vise un pic important de chlorophyle B, et l'UV tape un plateau correcte pour la A et un peu la B

[5] Sur la durée de l'expérience, à savoir un peu plus de 10 jours, l'horloge de l'Atmega8 avait pris un peu plus d'une heure de décalage.

[6] Avec une forte variance, en gros entre 0.5 et 1.4

dimanche, janvier 22 2012

Du capitalisme

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 bounty[3] 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)
  • <troll>que le code de Drupal est plus sécurisé que celui de Wordpress</troll> (ou que mes outils lui sont moins adaptés et/ou que j'ai eu moins de chance avec Drupal qu'avec Wordpress).

Notes

[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

jeudi, décembre 2 2010

Man(i)on(s) des sources

Depuis quelques années le fuzzing a beaucoup fait parlé de lui, et il m'est d'ailleurs déjà arrivé de jouer un petit peu avec et d'y faire allusion sur ce blog. En revanche ce qui, d'après ce que je perçois, est complètement passé de mode c'est l'analyse de code source. Trouvant ça bien dommage je me suis penché sur ce qui existait pour analyser du code PHP...

Sleepy Pixy - Creative Common by "Alkan de Beaumont Chaglar" on Flickr
D'abord soyons clair : ce que je cherche à identifier à partir de code source PHP ce sont exclusivement des failles de sécurité. En aucun cas je ne vais m'attacher à trouver de potentiels bugs (utilisation de variables non déclarées, ...) ou problèmes de performances ($variable++ à la place de ++$variable, ...). En résumé je recherche donc des LFI, des XSS, et des SQLi :)

J'ai ainsi farfouillé un petit peu le net à la recherche d'outils d'analyse de code source PHP qui répondrait à mes attentes et ce qui m'a semblé être la seule solution (Open Source) viable c'est pixy. Pixy est un petit soft codé en Java qui tente d'identifier des XSS et des SQLi grâce à une recherche par teinte[1] à partir de code source PHP.

Quelques téléchargements sur sourceforge et exploit-db plus loin en guise de tests j'identifie plusieurs points marquants de pixy :

  • Il y a peu de faux positif. Quand pixy repère quelque chose, c'est généralement vrai :)
  • pixy ne sait pas repérer les points d'entrées dans un projet PHP, on doit manuellement lui spécifier un à un les fichiers PHP à étudier (il se débrouille en revanche correctement avec les includes :)). Personnellement ça s'est fini avec un find -name *.php -exec ... ;-)
  • pixy n'est pas du tout compatible PHP5...et c'est bien dommage parce que l'écrasante majorité des softs PHP que l'on trouve de nos jours sont en PHP5
  • plus dommage encore : pixy n'est plus mis à jour depuis 2007 et il n'est pas prévu qu'il supporte PHP5 un jour...
  • pixy plante parfois souvent (mais c'est généralement à cause de fichiers en PHP5 :( )

Du coup j'ai poursuivi ma recherche et je suis tombé sur ce papier très sympa (et récent qui plus est) ! En gros il s'agit d'une étude de sécurisation des applis PHP de façon automatisé par analyse de code (bref : pile le sujet de ce billet) et les conclusions[2] en sont qu'il faut soit utiliser des applis propriétaires aux algorithme obscurs, soit utiliser pixy bien qu'il soit vieux/bancale et pas vraiment utilisable de façon sérieuse, soit se tourner vers l'avenir en espérant que quelqu'un fasse quelque chose basé par exemple sur PHC.

Qu'est-ce-que PHC pensez vous en ce moment ? C'est un compilateur de PHP. :) ...Si vous ne voyez pas le rapport avec la choucroute (après tout, transformer du PHP en exécutable et rechercher des vulns dans du code source PHP ce sont deux choses bien différentes) vous y verrez peut-être plus clair quand vous saurez que PHC est capable de transformer du code PHP en 3 autres types de représentations intermédiaires (AST, HIC et MIC) et qu'il peut sortir le code transformé (en AST, MIC, ou HIC) au format "texte" ou au format XML. Donc en utilisant PHC vous avez un outil capable de transformer un code source PHP en une représentation de langage plus abstraite, au format texte ou XML, que vous pouvez alors traiter beaucoup plus facilement dans le but d'y faire une recherche par teinte :) Bon, bien sur, ce n'est donc pas une solution "clef en main" d'analyse de sécurité d'applis PHP à partir des sources (puisqu'il faut en fait re-coder toute la recherche par teinte), mais c'est tout de même une base solide qui pourrait permettre d'élaborer un petit moteur d'analyse assez rapidement.

L'un d'entre vous se sent inspiré... ;) ? Bon bah en attendant je continuerai d'utiliser pixy ^_^

Notes

[1] Un peu comme ce que font d'autres personnes avec valgrind pur du code compilé.

[2] Conclusions TRES résumés par mes soins, je vous invite à lire le sujet original pour en avoir une vision plus complète