Mot-clé - Reverse Engineering

Fil des billets - Fil des commentaires

lundi, mai 20 2013

Dissection de programmes sous linux

J'ai longtemps pensé que pour s'initier au reverse le chemin "standard" consistait à apprendre à débuguer ses propres programmes autrement qu'à coup de printf. Avec le recul je me dit qu'il y a beaucoup d'autres chemins, et j'ai bien envie de partager avec vous celui qui consiste à observer les programmes des autres :) J'avais déjà parlé de python-ptrace qui permet de faire des trucs très sympa, mais aujourd'hui on va découvrir ensemble beaucoup d'autres astuces d'ingénierie inverse dans le but d'analyser le fonctionnement d'une application flash. Accrochez votre ceinture et re-mobilisez toutes les connaissances de base que vous avez sur le fonctionnement d'un PC parce qu'il va y avoir de la variété dans les techniques (mal) employées dans cet article-fleuve !

Engin de chantier - Based on a Creative Common photo published by Elvert Barnes on Flickr
Un avertissement s'impose : je suis pentesteur de métier, pas réverseur, donc j'opère dans ce domaine en amateur et j'utilise certainement beaucoup de détours peu efficaces pour arriver au même résultat que ce qu'un pro obtiendrait de façon plus élégante et rapide. Donc si vous retenez quoique ce soit de cet article vous êtes maintenant prévenus : c'est de l'amateurisme et il y a certainement pleins de choses qu'il ne faut pas faire comme je vais l'exposer.

Plantons maintenant le décor. Slow Frog (un français !) expliquait en 2011 comment il avait écrit un bot en python pour jouer à sa place à un petit jeu flash consistant à tenir une pizzeria. Le jeu était simple et l'article très amusant. J'avais plus ou moins oublié cet article jusqu'à ce que je tombe sur une conférence de deux gars ayant codés des bots pour des jeux plus conséquents[1] et je me suis alors dit que j'allais tenter le coup sur un jeu flash plus compliqué.

Petite digression à cette étape du récit : écrire un bot est probablement contre les CGU du jeu donc je ne vais pas le citer publiquement dans cet article (même si je doute que qui que ce soit ai envie de me chercher des noises pour avoir "triché" à un petit jeu flash). Sachez juste qu'il s'agit d'un jeu assez largement plus complexe que celui de la pizzeria, et qu'il fait intervenir un nombre non-négligeable d'information textuelle et/ou numériques.

Bref, je me suis donc dit que j'allais tenter d'écrire un bot pour ce petit jeu flash juste pour vérifier si j'en étais bien capable. La première optique emprunté était la plus intuitive : l'approche graphique. Le concept est simple : je prends un screenshot, puis je l'analyse. Pour ce faire j'ai mobilisé 3 briques logicielles de bases :

Ce qui m'a posé le plus de problème s'est avéré sans conteste la lecture des textes. En effet, la police utilisée était petite ce qui rendait la lecture difficile et les erreurs n'étaient pas rare (l'OCR se plantait environ une fois sur dix...ce qui est énorme dans le contexte du jeu qui m'intéresse). J'ai donc codé des vérification de cohérences entre chaque intervention de l'OCR, ce qui a pas mal aidé mais ne donnait toujours pas un résultat parfait. Après plusieurs mois à améliorer le système de temps en temps j'ai obtenu un taux de succès de 100% d'identifications correctes sur les icones diverses du jeu, mais toujours pas un taux de reconnaissance acceptable sur les informations textuelles. J'ai donc laissé tombé le projet, lassé de voir mon bot prendre des décisions farfelues toutes les 5mn sur la base d'information mal lues.

Plusieurs mois après je me suis remis à la tache, en décidant d'intercepter les communications entre le jeux flash et le serveur du jeu plutôt qu'en essayant de "lire" l'écran. En effet, l'information transmise par le serveur est déjà dans un format compréhensible par un logiciel, autant en profiter. Autre avantage de cette technique : les outils impliqués sont ceux que j'ai l'habitude de manier lorsque je fais des pentests web. Aussitôt pensé aussitôt fait : j'intercale un proxy d'interception entre mon navigateur web et internet. Déception : le jeu refuse de démarrer. Je passe le proxy en transparent : même problème. Je fabrique ma propre autorité de certification racine, je l'intègre aux autorité de confiance de mon navigateur, puis de mon OS, et je l'utilise pour générer dynamiquement les certificats SSL bidons à présenter au navigateur[4]. Hélas, j'ai toujours le même problème : le jeu flash refuse catégoriquement de contacter le serveur de jeu via mon proxy. Tristesse, déception, et incompréhension.

Qu'à celà ne tienne, je n'ai qu'à descendre plus bas dans l'OS pour intercepter ces communications réseau ! L'astuce à laquelle je pense alors est celle de LD_PRELOAD. Sous linux la variable d'environnement LD_PRELOAD permet de forcer le chargement d'une librairie partagée avant toutes les autres, ce qui autorise la surcharge de fonctions issues des librairies légitimes. Par exemple si je code une fonction printf puis que je la compile dans une librairie partagée et que je force le chargement de cette librairie en priorité via LD_PRELOAD, l'ensemble des processus que je lancerai ensuite feront appel à mon implémentation de printf plutôt qu'à celle de la libc :) L'idée derrière cette astuce c'est de surcharger les fonctions de communication réseau pour intercepter les informations envoyées et reçues dans le tunnel SSL[5].

Pour mettre en place cette astuce il va falloir que j'identifie quelles sont les fonctions susceptibles d'êtres utilisées par le jeu pour ses communications. Normalement la commande ltrace permet de tracer (i.e. afficher) l'ensemble des appels à des fonctions de librairies partagées qu'un programme effectue. L'utilisation aurait donc été immédiate dans mon cas : je lance ltrace sur le processus du plugin-container de firefox faisant tourner le jeu, je cherche dans les fonctions qui sont affichées celles qui ont un lien avec des communications SSL, puis je les re-code afin de les surcharger avec LD_PRELOAD pour intercepter les informations en transit. Oui mais voilà : chez moi ltrace fait systématiquement planter firefox :( . J'ai essayé de restreindre son champs d'investigation en ne demandant que les fonctions de certaines librairies (pensant que, peut-être, c'était la latence ajoutée qui faisait planter le soft) mais rien n'y fait : impossible d'utiliser ltrace :(

De déception j'ai alors tenté de tracer uniquement les appels systèmes (avec le plus standard strace), ce qui a marché à merveille. Malheureusement je me suis retrouvé noyé dans une tonne d'appel système avec peu d'espoir d'y trouver quoi que ce soit en rapport avec SSL de toute façon.

Après cette mini digression vers les appels système je suis retourné aux librairies partagées. Si je ne pouvais pas tracer les appels effectivement réalisés, je pouvais au moins tenter de les deviner. Pour ce faire j'ai dumpé la table de liaison dynamique du plugin flashplayer grace à la super commande objdump[6] :

$ objdump -T /opt/Adobe/flash-player/flash-plugin/libflashplayer.so

/opt/Adobe/flash-player/flash-plugin/libflashplayer.so:     file format elf32-i386

DYNAMIC SYMBOL TABLE:
00000000      DF *UND*	00000000  GLIBC_2.1   iconv
00000000      DF *UND*	00000000              gtk_main_iteration
00000000      DO *UND*	00000000              gtk_major_version
...
00000000      DF *UND*	00000000  NSS_3.4     CERT_DecodeCertFromPackage
00000000      DF *UND*	00000000              gdk_window_set_back_pixmap
00000000      DF *UND*	00000000              gdk_screen_get_display
00000000      DF *UND*	00000000              XFreeGC
00000000      DF *UND*	00000000              gtk_entry_get_text

L'option "-T" d'objdump affiche la liste des fonctions importées par le soft ciblé, ainsi que, parfois, la librairie dont elle est tirée. En lisant ces importations je n'ai réussi à identifier qu'un seul appel interessant pour l'interception de communications chiffrées : PR_Read[7]. Tant mieux pour moi, ça ne fait qu'un "suspect" à auditionner ! Pour la petite histoire sachez que cette fonction fait partie des utilities fournis par le framework Mozilla et qu'elle permet de lire dans une socket abstraite (qu'elle soit dotée d'une couche SSL ou non ne change pas l'appel à la fonction). Voici donc la surcharge que j'ai écrite :

#define _GNU_SOURCE //obligatoire pour utiliser "dlsym" qui n'est à priori pas POSIX. Plus d'info ici : http://linux.die.net/man/3/dlopen
#include <prio.h> //Pour avoir les headers mozilla
#include <stdint.h> 
PRInt32 PR_Read(PRFileDesc *fd, void *buf, PRInt32 amount) {
	// D'abord je retrouve la "vrai" fonction PR_Read
	static PRInt32 (*real_PR_Read)(PRFileDesc*, void*, PRInt32) = NULL;
	real_PR_Read = dlsym(RTLD_NEXT, "PR_Read");
	// Maintenant j'appelle la "vrai" fonction PR_Read
	PRInt32 res = real_PR_Read(fd, buf, amount);
	
	// Enfin je stocke les données reçus si jamais il y en a.
	if (res>0){
		FILE* f = fopen("/tmp/debug.log","a");
		fprintf(f, "PR_Read : %d\n",res);

		int i; char* mybuf = (char*) buf;
		fprintf(f, "<<<\n");
		for (i=0; i<res; i++) {
			if ((mybuf[i]>8) && (mybuf[i]<127)) {
				fprintf(f, "%c", mybuf[i]);
			} else {
				fprintf(f, "%x", mybuf[i]);
			}
		}
		fprintf(f, "\n>>>");
		fclose(f);
	}
	return res; // Et, bien sur, je retourne le résultat renvoyé par la "vrai" fonction PR_Read
}

La ligne de compilation ressemble à ça : gcc -O2 -I/usr/include/nspr -I/usr/include/nss -shared -ldl -fPIC -o surcharge.so surcharge.c

Les deux -I sont pour avoir les includes de prio.h (en fait je n'ai besoin que de l'un des deux, mais je ne sais plus lequel donc, de paresse, j'ai laissé les deux). Le -shared c'est parce que je veux compiler en librairie partagée, le -fPIC c'est pour obtenir du code qui fonctionne indépendament de sa position en mémoire (je me demande si le -shared n'inclus pas cette option d'ailleurs...) et le -ldl c'est pour être linké avec la librairie de link permettant de retrouver les fonctions originales que je surcharge via dlsym.[8]

Une fois compilé en *.so l'utilisation de ma fonction d'interception se fait comme ça :

$ export LD_PRELOAD="/home/ozwald/surcharge/surcharge.so"
$ firefox http://urldujeu.lan #Là on utilise normalement son programme
$ unset LD_PRELOAD # Une fois qu'on a fini on supprime la variable LD_PRELOAD pour que tout redevienne normal

Bonne surprise : quand j'utilise firefox mon fichier /tmp/debug.log contient bien des informations ! Mauvaise surprise : les informations contenues sont (très ? (trop ?)) nombreuses et à priori sans aucun rapport avec les actions du jeu (grace à un tail -f j'ai pu constater que, souvent, des actions se déroulaient au niveau du jeu mais ne déclenchaient aucune écriture dans le fichier de log). Déception...je n'ai visiblement pas intercepté la bonne fonction.

Appliquant le proverbe orc "quand ça ne marche pas en poussant, pousse plus fort" j'ai décidé de surcharger plus de fonctions. J'ai donc fait un plus simple objdump -x sur le plugin flash pour obtenir la liste des librairies linkées au lieu des fonctions. Dans le tas j'ai trouvé plusieurs librairies relatives à la communication et/ou au SSL :

Dynamic Section:
...
  NEEDED               libssl3.so
  NEEDED               libnss3.so
  NEEDED               libnssutil3.so
  NEEDED               libnspr4.so
...

Partant de cette liste j'ai identifié plusieurs fonctions appartenant à ces librairies et qui pourraient tremper dans de la communication. J'ai donc surchargé : PR_Read, PR_Recv, SSL_read, BIO_read, et BIO_gets !

Comme on pouvait s'y attendre ça a été un échec pitoyable. Aucune de ces fonctions additionnelles n'est utilisée par le jeu :(

La méthode orc ne fonctionnant visiblement pas j'ai opté pour...la méthode orc ! "Quand ça ne marche pas en poussant, pousse plus fort" (je suis parfois tétu), donc j'ai surchargé strncpy, strcpy, recv, fread, read, strtok, XDrawString, et Xutf8DrawString.

Cette méthode très subtile m'a octroyé une petite victoire : j'obtient des informations qui semblent correspondre aux évènements du jeu. Visiblement certaines de ces fonctions sont utilisées pour peupler la petite fenêtre de log qui résume les évènements de jeu en bas d'écran; donc j'obtient pas mal d'informations! Malheureusement je me suis vite rendu compte que celà ne suffirait pas pour écrire un bot robuste. En effet certaines informations étaient manquantes, il y avait énormément de "bruit", et la cohérence temporelle n'était pas assurée (i.e. certains évènements m'étaient remontés dans un ordre différent de ceux dans lequel ils se produisaient dans le jeu...je blame le multithread sur le coup).

Là j'ai l'impression d'être face à un mur... Devant mon incapacité à expliquer l'échec de la surcharge de PR_Read & co ainsi que l'échec silencieux de la méthode d'interception via proxy avec un certificat SSL pourtant "valide" je me suis dit que, peut-être, c'était le plugin flash qui faisait de la magie noire. Je me suis donc renseigné et j'ai trouvé Gnash et Lightspark qui sont deux logiciels complémentaires réalisant une implémentation libre d'un interpreteur flash. Rien de tel qu'un logiciel libre pour comprendre le fonctionnement de quelque chose donc j'ai installé gnash / lightspark et j'ai tenté de lancer le jeu. Malheureusement lightspark a planté :-( C'était prévisible de la part d'un logiciel jeune et dont les spécifications proviennent en grande partie de difficiles efforts d'ingénierie inverse du plugin flash officiel. J'ai forcé un petit peu dans cette voie en récupérant les versions de dévelopement[9] de gnash et lightspark et j'ai re-tenté le coup avec les même résultats (i.e. plantage de lightspark).

Je me retrouve donc encore une fois coincé...une nouvelle approche s'impose ! Je vais dumper la mémoire du processus grace à /proc/PID/maps et /proc/PID/mem dans l'espoir de trouver des choses intéressantes. Dans l'esprit j'étais parti pour faire quelque chose à la memory eye en fait.

Pour ceux qui l'ignore voici un petit résumé de l'esprit des fichiers que je vais utiliser : Sous linux le pseudo-système de fichier /proc/ contient pleins d'information sur le fonctionnement en cours du système. Par exemple /proc/cpuinfo contient des informations sur votre processeur. Chez moi il contient ça :

$ cat /proc/cpuinfo
processor	: 0
vendor_id	: AuthenticAMD
cpu family	: 16
model		: 6
model name	: AMD Athlon(tm) II X2 250 Processor
...

En l'espèce nous allons nous intéresser aux fichiers /proc/PID/maps et /proc/PID/mem. Le plus simple à comprendre est /proc/PID/mem puisqu'il contient simplement la mémoire totale du système telle qu'elle est vue depuis le processus d'id PID. La mémoire adressable étant gigantesque nous allons cibler nos recherches grace à /proc/PID/maps qui contient la liste des segments de mémoire adressable qui sont effectivement alloués et accessibles par le processus en question. Pour faire un test vous pouvez lancer une commande "less" sur un fichier quelconque (ou juste un "top", comme vous préférez), récupérer son PID grace à ps aux | grep NomDeVotreCommande puis faire un cat sur le /proc/PID/map correspondant. Voilà ce que ça donne chez moi (j'ai lancé un top dans un autre shell):

$ ps aux | grep [t]op
ozwald    9064  0.0  0.0   2700  1136 pts/0    S+   12:33   0:17 top
$ cat /proc/9064/maps
08048000-08055000 r-xp 00000000 03:02 730853     /usr/bin/top
08055000-08056000 r--p 0000c000 03:02 730853     /usr/bin/top
08057000-0807b000 rw-p 00000000 00:00 0          [heap]
...
b76f1000-b76f2000 rw-p 00185000 03:02 938394     /lib/libc-2.15.so
...
b7739000-b773a000 rw-p 00044000 03:02 417799     /lib/libncurses.so.5.9
...
bfc5c000-bfc7e000 rw-p 00000000 00:00 0          [stack]
...

Comme vous pouvez le voir nous obtenons des informations pour chaque plage allouée. En particulier nous avons :

  • l'adresse de début (0xbfc5c000 pour la stack par exemple)
  • l'adresse de fin (0xbfc7e000 pour poursuivre notre exemple de la stack)
  • les permissions ("rw-p" pour la stack)

Nous pouvons donc à présent cibler toutes les plages qui sont à la fois "R"eadable et "W"ritable par le processus, et y chercher des élèments parlant. Pour lire le contenu de ces zones mémoire il suffit d'ouvrir /proc/PID/mem en lecture seule, puis de faire un seek jusqu'à l'offset de début de plage, et à y lire autant d'octets que la taille de la plage. Le petit script python[10] ci-dessous permet de dumper les plages mémoire du processus dont on passe le PID en paramètre :

#! /usr/bin/env python
import re
import sys
if len(sys.argv) != 2 :
	print "Merci de donner un PID en argument"
	print "Usage : %s PID"%sys.argv[0]
	sys.exit(1)

mypid=sys.argv[1]
mypid=str(mypid)
sys.stderr.write("PID = " + str(mypid) )
maps_file = open("/proc/"+mypid+"/maps", 'r')
mem_file = open("/proc/"+mypid+"/mem", 'r', 0)
for line in maps_file.readlines():  # for each mapped region
	m = re.match(r'([0-9A-Fa-f]+)-([0-9A-Fa-f]+) ([-r][-w])', line)
	if m.group(3) == 'rw':  # if this is a writeable region
		sys.stderr.write("\nOK : \n" + line+"\n")
		start = int(m.group(1), 16)
		if start > 281474976710655 :
			continue
		end = int(m.group(2), 16)
		sys.stderr.write( "start = " + str(start) + "\n")
		mem_file.seek(start)  # seek to region start
		chunk = mem_file.read(end - start)  # read region contents
		open("%d.dump"%start,'w').write(chunk) # dump contents to a file
	else :
        	sys.stderr.write("\nPASS : \n" + line+"\n")
maps_file.close()
mem_file.close()

Bon, avec un tel outil les perspectives d'analyse sont démultipliées ! Je lance donc le jeu, récupère le PID de l'interpreteur flash officiel via un ps aux | grep [f]lash, et dump le contenu de sa mémoire en invoquant le script ci-dessus. Je me retrouve avec quelques dizaines de fichiers de dump, chacun correspondant à une plage mémoire. Après quelques grep bien sentis[11] j'identifie des structures JSON qui semblent contenir des éléments de jeu et qui ressemblent à ça :

GameEvent:ClientArrival { "ClientID":"123", "ClientName":"Roger", ..}
GameStatus:OrdersWaiting { "Orders":[ {"ClientID":"123", "Product":"Pizza", ...}, {}, ..., {}] }

L'espoir renait parce que ces structures sont très intéressantes : d'une part elles contiennent toutes les informations dont j'ai besoin pour écrire un bot, et d'autre part le fait qu'elles soient en JSON me laisse penser qu'il s'agit bien là de l'information échangée en réseau dans le tunnel SSL et sur laquelle j'essaie de mettre la main depuis le début. J'ai donc creusé dans cette voie pour, finalement, obtenir un script python qui fonctionne en deux temps :

  1. Il identifie la zone mémoire où sont les structures JSON
  2. Une fois la zone identifiée avec certitude il dump cette zone en boucle en guettant des changements (ce qui signifierait l'arrivée d'un nouveau paquet d'information en provenance du serveur et donc l'arrivée d'un nouvel élément de jeu tel qu'un client).

La qualité d'information que j'ai obtenu avec ce script est exemplaire puisque, contrairement à la lecture de l'écran par OCR, je n'ai aucune erreur sur le contenu des texte. Malheureusement, lorsque plusieurs évènements se suivent très rapidement dans le temps (comme deux clients qui rentrent quasiment en même temps dans la pizzeria) mon script ne perçoit que l'un des deux évènements et rate l'autre qui se fait écraser en mémoire entre deux dumps. Il fallait s'y attendre puisque je fait du "poll" sur la mémoire au lieu d'avoir obtenu un système en "push" comme me le permettrait la surcharge d'une fonction par LD_PRELOAD :(

N'ayant pas envie d'abandonner j'ai poursuivi dans une "voie du milieu[12]" tirant partie de plusieurs des travaux effectués jusqu'à présent. Lorsque je dumpais les structures JSON directement depuis la mémoire j'ai remarqué que l'adresse où étaient les structures intéressantes ne bougeait quasiment jamais lors d'une même partie. Ces structures JSON n'arrivant pas là par magie (à moins que le plugin flash officiel pratique réellement la magie noire...) je me suis dit qu'identifier la fonction responsable de l'écriture de cette structure serait très intéressant puisque je pourrait peut-être la surcharger avec LD_PRELOAD.

La démarche que j'ai adopté a donc été la suivante :

  1. Lancer une partie
  2. Identifier le PID de l'interpreteur flash par ps aux | grep [f]lash
  3. Dumper la mémoire du processus et identifier l'adresse d'une structure JSON d'intérêt
  4. Attacher gdb au processus de l'interpreteur flash
  5. Poser un breakpoint sur les écritures à l'adresse de la structure JSON
  6. Afficher, automatiquement lors du déclenchement de ce breakpoint, le contenu de la mémoire (pour vérifier si j'ai bien une structure JSON comme je le pensait) ainsi que la backtrace des 4 derniers appels.

L'objectif de ce protocole étant d'identifier quelle partie de code est responsable de l'écriture de ces structures. En termes de commande voici ce que ça a donné :

$ ps aux | grep [f]lash
ozwald    9064  0.0  0.0   2700  1136 pts/0    S+   12:33   0:17 top
$ python memory_dump_and_seek.py 9064
Dumping...
Seeking json...
The json object is at address 0xaa72f000
$ gdb
(gdb) attach 9064
(gdb) watch *0xaa72f000
Hardware watchpoint 1: *0xaa72f000
(gdb) commands 1
>silent
>x/1s 0xaa72f000
>bt 4
>cont
>end
(gdb) cont
Continuing.
0xaa72f000:	"GameEvent:ClientArrival { "ClientID":"123", "ClientName":"Roger", ..}...
#0  0xb584c026 in ?? () from /lib/libc.so.6
#1  0x00000277 in ?? ()
#2  0xb2b2c1d9 in ?? () from /opt/Adobe/flash-player/flash-plugin/libflashplayer.so
#3  0xb2b33f9b in ?? () from /opt/Adobe/flash-player/flash-plugin/libflashplayer.so
0xaa72f000:	"GameEvent:ClientArrival { "ClientID":"124", "ClientName":"Paul", ..}...
#0  0xb584c026 in ?? () from /lib/libc.so.6
#1  0x00000277 in ?? ()
#2  0xb2b2c1d9 in ?? () from /opt/Adobe/flash-player/flash-plugin/libflashplayer.so
#3  0xb2b33f9b in ?? () from /opt/Adobe/flash-player/flash-plugin/libflashplayer.so
0xaa72f000:	"GameEvent:ClientArrival { "ClientID":"125", "ClientName":"Jean", ..}...
#0  0xb584c026 in ?? () from /lib/libc.so.6
#1  0x00000277 in ?? ()
#2  0xb2b2c1d9 in ?? () from /opt/Adobe/flash-player/flash-plugin/libflashplayer.so
#3  0xb2b33f9b in ?? () from /opt/Adobe/flash-player/flash-plugin/libflashplayer.so
...

Voilà qui sent bon. A chaque interruption :

  • la zone mémoire contient bien ce qui ressemble à une structure JSON valide
  • la backtrace est systématiquement la même
  • cerise sur le gateau : la dernière instruction appelée (i.e. celle qui est responsable de l'écriture mémoire) appartient à /lib/libc.so.6 et sera donc surchargeable via LD_PRELOAD (alors que si ça avait été une fonction interne à l'interpreteur flash j'aurai été plus ennuyé).

Par contre ce qui me surprend à ce moment là c'est que j'avais déjà fait des tentatives infructueuses en surchargeant une bonne pelleté de fonctions de la libc (strcpy et strncpy en particulier, souvenez-vous du début de cet article...il y a 3 pages :D ). Quelle fonction de la libc peut donc être responsable de ces écritures ? A cette étape je suis certain qu'un gourou de gdb pourrait répondre en une commande. Malheureusement je ne suis pas un gourou de gdb :( J'ai bien tenté de demander gentimment, mais sans succès :

(gdb) info symbol 0xb584c026
No symbol matches 0xb584c026.

Bon..."Quand ça ne marche pas en poussant, pousse plus fort" donc je vais adopter, encore une fois, une technique très subtile :

  1. Tout d'abord on active l'enregistrement des sorties de gdb dans un fichier texte, en prévision d'un gros tas de donnée à traiter : set logging on
  2. On demande à gdb d'afficher TOUTES les fonctions que le processus connait[13] : show functions.

Une fois ceci fait on quitte gdb et on se retrouve avec un fichier "gdb.txt" qui contient les logs de la session retranscrivant ce que nous avons eu sur la sortie standard et ressemblant à ça :

All defined functions:

Non-debugging symbols:
0x08049290  _init
0x080492b8  strerror_r@plt
0x080492c8  abort@plt
0x080492d8  sysconf@plt
...
=== NDLR : environ 40 000 lignes plus tard ===
...
0xb470e8f0  _nss_dns_getnetbyaddr_r
0xb470ec40  _nss_dns_getcanonname_r
0xffffe400  __kernel_sigreturn
0xffffe40c  __kernel_rt_sigreturn
0xffffe414  __kernel_vsyscall

Avec ces informations, retrouver la fonction que je cherche est simple comme bonjour puisqu'un grep et un sort suffisent. Pour rappel je cherche la fonction de la libc qui contient l'adresse "0xb584c026" puisque c'est l'instruction à cette adresse qui est responsable de l'écriture de la structure JSON que je recherche à l'adresse 0xaa72f000 :

$ grep -E 0xb584[bc] gdb.txt | sort -u
...
0xb584bea0  __strncasecmp_l
0xb584bea0  strncasecmp_l
0xb584bf20  memccpy
0xb584bf80  memcpy
0xb584c680  __strsep_g
0xb584c680  strsep
...

La coïncidence est trop belle : c'est memcpy le "coupable" (puisque 0xb584bf80 < 0xb584c026 < 0xb584c680) ! Il ne me reste donc plus qu'à surcharger memcpy pour vérifier la théorie. Attention cependant : surcharger strcpy et strncpy ne constituait pas vraiment un risque (ces fonctions sont censées traiter des chaines de caractères), mais surcharger memcpy est bien plus audacieux. En effet, memcpy est d'un usage beaucoup plus versatile et tout aussi courant (si ce n'est beaucoup plus). Quelques précautions s'imposent donc lors de l'écriture de la surcharge afin de s'assurer que l'on ne va intercepter que les mouvements de mémoire qui nous intéresse. D'une part ça nous facilitera le traitement des données interceptées et, d'autre part, ça va permettre de limiter le ralentissement des processus que nous surveillons même s'ils font très souvent appel à memcpy. J'ai donc adopté les précautions suivantes :

  • Je n'ai utilisé aucune tournure qui pourrait faire appel à une primitive memcpy lors de l'optimisation du compilateur (je ne sais pas s'il y a un risque d'appel récursif, mais je préfère ne pas tenter).
  • J'ai utilisé un fichier de dump différent par processus et par thread afin d'éviter les problèmes d'accès concurrents (j'aurai pu jouer avec des mutex, mais ça aurait potentiellement ralenti le schmilblick et puis c'est plus long à coder)
  • J'ai fait attention à ne pas trop introduire de bug dans mon code. Ca a l'air évident mais ça ne coute rien de le rappeler. Par exemple : avant d'accéder aux éléments de csrc pour vérifier si la zone mémoire copiée commence bien par la chaine de caractère que je veux ("Game") je m'assure que csrc contient au moins autant de caractères que ce que je vais lire...

Bref, voilà le code :

#include <sys/syscall.h> //for gettid
#include <sys/types.h> // this and below for getpid
#include <unistd.h>
void *memcpy(void *dest, const void *src, size_t n){
	static void* (*real_memcpy)(void* , const void*, size_t) = NULL;
	real_memcpy = dlsym(RTLD_NEXT, "memcpy");

	const char* csrc = (const char*) src;

	if ((n>4) && (csrc[0]==71/*G*/) && (csrc[1]==97/*a*/) && (csrc[2]==109/*m*/) && (csrc[3]==101/*e*/)){
		int write_this_much = 0;
		// I only want printable ascii :
		while ((write_this_much<n) && (csrc[write_this_much]>31) && (csrc[write_this_much]<127) ) { write_this_much++; }

		// Un fichier par processus et par thread :
		char filename[128];
		snprintf(filename,128,"/tmp/debug_%d_%d.log\0", (int)getpid(), (int)syscall(SYS_gettid) );

		FILE* f = fopen(filename,"a");
		fprintf(f, "memcpy : <<< ");
		fwrite(csrc, 1, write_this_much, f);
		fprintf(f, ">>>\n");
		fclose(f);
	}
	return real_memcpy(dest, src, n);
}

Malgré toutes ces précautions lorsque j'utilise ma surcharge en déclarant la librairie dans LD_PRELOAD firefox crashe lamentablement au démarrage :-( ...Et c'est là que j'ai un gros coup de chance : chromium-browser, lui, fonctionne comme si de rien n'était[14] :) ! Je ne sais même pas pourquoi j'ai essayé sur chromium cette fois-là alors que je n'avais fait aucun test dessus auparavant, mais je m'en félicite ;)

Bon, avec un navigateur qui marche je vais sur le jeu flash, et je me fait une petite partie. Une fois la partie terminée j'ouvre /tmp/debug_8613_8613.log et je constate avec joie qu'il contient l'ensemble des structures JSON que je voulais ! Aucune corruption, à priori aucun manque, et l'ordre semble correct.

En conclusion donc : j'en aurai bien ch*é pour arriver à ce résultat et je ne comprends pas encore tout (pourquoi firefox plante-t-il ? Est-ce-que le plugin flash embarque sa propre librairie SSL ?? Pourquoi ltrace fait-il planter les softs qu'il surveille ? etc.), mais j'ai également appris beaucoup (dumper proprement la mémoire d'un process, définir les commandes à lancer automatiquement quand gdb déclenche un breakpoint, définir un breakpoint sur une écriture en mémoire, ...) et surtout : J'ai réussi à faire ce que je voulais[15] :-D !!!

Notes

[1] Eux, avaient une motivation pécuniaire, contrairement à Slow Frog.

[2] En guise de rafinnement je prenais le screenshot dans un répertoire appartenant à un volume monté en tmpfs histoire d'être certain de ne pas fatiguer le disque par les écritures de screenshot répétées

[3] J'ai également testé tesseract, un autre logiciel de reconnaissance de caractère (OCR), mais j'ai trouvé qu'il donnait globalement des résultats moins bons.

[4] Merci OpenSSL et BURP :)

[5] Avec cette même fonctionnalité de LD_PRELOAD certains ont réalisé des keylogger, des rootkits, etc.

[6] Vous pouvez également utiliser nm -D à la place de objdump -T

[7] Je ne connaissais pas cette fonction avant de tomber dessus lors de ces recherche, je l'ai donc identifiée par tatonnement.

[8] Pfiou ça en fait des options de gcc...J'espère que je n'ai pas dit trop de bétises d'ailleurs :-D

[9] J'aime bien l'expression "bleeding edge" plutôt que "version de développement", mais bon...limitons les anglicismes quand ils ne sont pas nécessaires ^^

[10] Script largement pompé depuis le net; googlez pour retrouver la source originale, je ne l'ai malheureusement pas noté.

[11] Par exemple j'ai lancé des grep sur le nom des clients de la pizzeria que je pouvais voir à l'écran lors du dump de la mémoire.

[12] Comme le diraient certains sages.

[13] Attention, dumper l'ensemble des fonctions retourne beaucoup de résultats et ça peut donc prendre du temps. Dans mon cas pratique celà signifiait que le freeze du jeu était assez long pour me faire perdre la partie. Etant donné que l'adresse d'enregistrement des JSON changeait à chaque démarrage de partie, dumper les fonctions devait être la dernière étape de mon processus d'analyse :)

[14] En fait chromium-browser rame assez notablement, mais il fonctionne sans montrer la moindre envie de planter.

[15] Bon, il me reste à remplacer les fichiers par des tubes nommés (mkfifo) puis à écrire la partie logicielle qui va lire le flux d'information en temps réel dans ces tubes, puis à écrire la partie "IA" qui va décider comment jouer, puis à écrire la partie qui va envoyer les actions au jeu...Mais le plus difficile est fait, si si je vous jure ;) D'ailleurs, le plus difficile étant fait, je ne sais pas si ça m'intéresse encore de terminer ce projet lol

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, juin 10 2012

SSTIC 2012 completed

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 paragraphe[1] 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ématiquement"[2].

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" <humour>et PAN dans tes dents langage pourri soit disant ultra-secure et portable :p</humour>.

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 respect[4]

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 temps[5]. 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 fonctionnelle[6]. 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ées[7].

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 symbolique[9] 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 questions[10].

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%.

Notes

[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] http://www.ozwald.fr/index.php?tag/SSTIC#pnote-36-2

[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.

mardi, août 30 2011

metasm, en mieux (ou pas)

Il n'y a que deux choses qui manquent à Python, à mon humble avis : metasploit, et metasm. Or il semblerait qu'il y a quelques jours/semaines, l'un de ces deux manques ait été comblé par miasm, l'équivalent de metasm en python ! J'étais donc obligé de faire au moins un petit billet là dessus :)

Engine - Creative Common by "cbowns" on Flickr
Comment installer miasm ? La page officielle du projet est relativement claire, mais ne s'applique pas immédiatement (en particulier quand on est sous gentoo). Voilà donc la démarche que j'ai suivi, ce n'est peut être pas la meilleure mais "chez moi ça marche"(c). D'abord voyons les dépendances :

  • Grandalf (https://github.com/bdcht/grandalf) in order to render graphical disassembler.
  • Modified libtcc (http://bellard.org/tcc/) to Jit code for emulation mode. see below
  • python-ply for parsing
  • numpy
  • python-virtualenv
  • python-dev
  • python-qt4

Allons y par étape en adaptant pour gentoo :

Grandalf viendra tout seul quand on clonera le méta-répertoire, on ne s'en occupe donc pas.

Concernant la libtcc on va suivre les instructions tout simplement : git clone git://repo.or.cz/tinycc.git puis on édite le Makefile conformément à ce qu'indique le site de miasm, puis make...échec texi2html: Command not found...Pas de problème emerge -v texi2html puis on re-tente le make : victoire ! Il ne reste plus qu'à make install.

Pour "python-ply" il faut en fait installer "dev-python/ply", sauf qu'il est masqué par le keyword x86. On démasque donc et on installe joyeusement : echo "dev-python/ply ~x86" >> /etc/portage/package.keywords && emerge -v ply

Pour "numpy" rien de plus simple emerge -v numpy.

Idem pour "python-virtualenv" qui s'installe sans poser de problème avec un simple emerge -v virtualenv

Pour "python-dev" c'est encore plus simple : rien à installer puisque nous sommes sous Gentoo :)

Enfin "python-qt4" est lui aussi assez simple à obtenir puisqu'il suffit d'un emerge PyQt4[1]

Maintenant on clone le répertoire hg clone https://code.google.com/p/smiasm/ smiasm...fail. Après un emerge -v hg-git ça ne se passe pas mieux...Après quelques recherches la version de mercurial stable sous gentoo est la 1.7, or le support des subrepository GIT n'apparait dans mercurial qu'à partir de 1.8 -_- ....bon...echo "=dev-vcs/mercurial-1.8.2 ~x86" >> /etc/portage/package.keywords && emerge -v =dev-vcs/mercurial-1.8.2...damned ça foire encore. Après un poil de trifouillage il semblerait que ça soit le clonage de grandalf qui foire...probablement à cause du .hgsub du répertoire smiasm qui pointe (à tort?) vers [git]https://github.com/bdcht/grandalf ...Bon on clone grandalf à la main git clone git://github.com/bdcht/grandalf.git, et également miasm parceque "chezmoiçaapasmarché"(c) hg clone https://code.google.com/p/miasm/ miasm -v --traceback ainsi que le README.txt qui est à la racine du repository smiasm et, plus important : pyMakefile et Makefile. Pfiou, tout ça ! Maintenant on revient sur le chemin tracé par le site officiel : on tape donc make && make install dans le répertoire de smiasm..victoire :) !!!

On teste si tout marche bien cd miasm/example/ && python disas_and_graph.py /bin/ls ...FAIL NameError: global name 'route_with_nurbs' is not defined

Bon, on re-trifouille et je vous fait grace des détails. Au final la méthode que j'ai employé (et qui marche sur gentoo et ubuntu 10.4 une fois les dépendances de chaque distro réglées) c'est :

  1. D'abord on se débarasse du problème de TCC en suivant à la lettre les instruction du site officiel smiasm : clone git://repo.or.cz/tinycc.git, ensuite on rajoute "-fPIC" dans les CFLAGS du fichier Makefile (CFLAGS+=-g -Wall -fPIC) puis on compile/installe : ./configure && make && make install
  2. Maintenant on attaque smiasm à proprement parler : On clone une première fois smiams : hg clone http://code.google.com/p/smiasm/, ça se termine avec un message d'erreur mais "pas grave". On télécharge ensuite à la main les fichiers "Makefile" et "pyMakefile" depuis l'accès HTTP au repository (http://code.google.com/p/smiasm/source/browse/)
  3. On clone à la main grandalf parce que le .hgsub de smiasm utilise une notation exotique qui n'est comprise ni par le mercurial gentoo par défaut ni par le mercurial ubuntu 10.4 par défaut : cd smiasm && rm -Rf grandalf && git clone git://github.com/bdcht/grandalf.git grandalf
  4. On fait un rollback de version de grandalf puisque les versions commitées depuis juillet dernier ne semblent plus compatibles avec miasm (disparition de la fonction route_with_nurbs) : git checkout a851b359185132645d9dce3d11037f3263604358
  5. Il ne reste plus qu'à compiler et installer smiasm :) ! cd .. && make && make install

A présent on peut tester le tout cd miasm/example/ && python disas_and_graph.py /bin/ls. Victoire :

miasm - test script

Il ne nous reste plus qu'à dévorer la documentation pointée par Sid[2] et à nous les joies du bas niveau avec encore plus de facilité ! A bientôt donc pour de nouveaux billets passionants (en tout cas j'espère qu'ils réussiront au moins à me passioner lors de leur rédaction lol) !

Notes

[1] Ce qui peut prendre pas mal de temps si jamais vous devez recompiler qt-core :( ...

[2] Merci d'ailleurs, sans ce blog post je ne l'aurai jamais trouvé lol

dimanche, octobre 24 2010

Dans l'estomac du python

Après un long silence sur ce blog (mais une longue période d'intense activité IRL) il est temps de résumer certains trucs qui m'ont occupé niveau informatique ces derniers temps :) ! Comme le titre le laisse présumer ça parle pas mal de python mais ne vous enfuyez pas pour autant si vous ne maitrisez pas ce langage de script sur le bout des doigts : je vais esquiver les détails gorets du code cette fois et me contenter de donner un aperçu high-level des possibilités qui sont offertes.

Cave - Based on a work published under Creative Common by "Kevin Lawver" on Flickr
J'en avais déjà parlé dans mon précédent billet mais j'insiste lourdement : pefile est une excellente extension python. Pour vous résumer certaines des fonctions qui me plaisent le plus :

  • ouverture, modification, puis sauvegarde du fichier PE modifié (il parait qu'il ne faut pas trop modifier la structure PE pour que ça marche, qu'à celà ne tienne il suffit de modifier "sur place" !)
  • accès ultra simple à toute la table d'importation du fichier PE (et donc éventuellement modification de cette dernière si on en a envie ;-))
  • accès ultra simple au contenu des diverses sections du PE et à leurs propriétés (donc éventuellement modification du contenu ou des propriétés...par exemple on peut rendre des sections "exécutable" ou "writable", je dis ça totalement au hasard... )
  • accès ultra simple à l'arbre des ressources du fichier PE (et donc éventuellement modification de ces ressources si le coeur vous en dit...)
  • cross platform !!! Ca c'est un vrai bonheur, les scripts qui utilisent pefile tournent sans modification sur linux ou windows.

Une autre extension super cool que j'ai découvert en jouant avec pefile : pydasm. C'est un binding python vers la librairie libdasm qui, comme son nom l'indique, permet de faire du désassemblage. Pour la petite histoire pydasm est livré avec pydbg dont je ne parlerai pas dans ce billet-ci mais que je vous conseille vivement de regarder si vous avez envie de jouer sous windows. Si on combine donc pefile avec libdasm on est en possession d'un vrai couteau suisse pour désosser et comprendre comment tourne un fichier PE donné.

Si vous avez tout suivi vous devez vous douter de ce que fait la prochaine extension dont je vais parler...On a du désossage et modification de fichier PE, on a du désassemblage de langage machine, il ne manque donc plus que....de l'assemblage :-D ! Et c'est là que vous allez (peut-être) être surpris : je ne vais pas parler de python dans ce paragraphe. Il y a bien des librairies d'assemblages pour python mais je n'ai, pour l'instant, été convaincu par aucune d'entre elles. En revanche j'ai été tout à fait convaincu par fasm qui cumule deux avantages non négligeables :

  • Il est open source
  • Il tourne aussi bien sous linux que windows

Donc tant pis pour le 100% python, je me suis laissé tenté par la simplicité absolue d'écrire un fichier temporaire[1] à partir de mon code python puis d'enchainer avec un petit

if re.match('win.*',sys.platform):
        system('FASM.EXE tmp.asm tmp.bin')
else:
        system('./fasm tmp.asm tmp.bin >> /dev/null')
assembly=open('tmp.bin','rb').read()

Bref, on a du désassemblage, on a de l'assemblage, on a de la manipulation de fichiers PE...je vous laisse imaginer tout seul ce qu'on peut faire avec ça parce que de mon coté je manque de "motif légitime" pour publier sur ce blog ce que j'en ai fait jusqu'à présent[2]

Enfin, le dernier bout de code python qui m'a occupé ces derniers temps c'est sulley. Pour ceux qui ne connaissent pas c'est un framework de fuzzing[3] qui permet de fuzzer des services accessibles par TCP ou UDP[4]. J'ai un petit peu joué avec et ça tourne pas mal; on peut très facilement avoir un script sulley qui tourne sur une VM windows afin de monitorer le processus cible alors que les autres processus sulley tournent sur une autre machine (au hasard une linux) et se chargent d'offrir une belle interface web de suivi de la campagne de fuzzing, de générer les requêtes réseau à destination du process à fuzzer, etc. Seule petite astuce à vous communiquer si vous voulez y jeter un oeil : si jamais vous galérez à installer pcapy ne vous prenez pas la tête plus de 2mn et allez plutôt directement faire de la boucherie dans network_monitor.py pour vous débarasser des appels à pcapy; en 10mn vous les aurez tous remplacés par l'équivalent en scapy ou carrément par des os.system("tcpdump blabla")[5].

Voilà, la prochaine étape sera peut-être de faire un binding amusant entre sulley et d'autres scripts python qui trainent dans mes cartons en les adaptants en pydbg...ou bien ça sera tout autre chose, allez savoir :) ! D'ici là : geekez bien ;)

Notes

[1] Pour info, si vous voulez faire propre, vous pouvez utiliser os.tempnam ou os.tmpfile à la place de toujours réutiliser 'tmp.bin'.

[2] En revanche je ne manquais pas de motif légitime pour en faire profiter mes collègues pentesteurs, c'est déjà ça. D'ailleurs l'un d'entre eux m'a fait remarquer qu'un certain "Nick Harbour" avait fait des choses similaires en 2008, si ça vous intéresse d'aller jeter un oeil ... ;-)

[3] Moins complet que Peach mais infiniment plus simple à prendre en main, ce qui explique à 100% pourquoi je l'ai préféré à Peach :)

[4] Pas de fuzzing de fichier donc, ni de ligne de commande, ou autre.

[5] c'est quand même très moche de faire ça à coup de os.system('tcpdump blabla') puis os.system("killall tcpdump"), préférez scappy qui sera bien plus précis et moins lourd (faites ce que je dis, ne faites pas ce que je fais ^^)

- page 1 de 2