Fichiers Polyglottes : Ou comment avoir 4 fichiers en un
Au SSTIC de cette année, une des conférences qui m'a le plus interessé était celle présentée par Ange Albertini et intitulée "Polyglottes Binaires et Implications". J'y ai en particulier découvert les fichiers polyglottes. J'ai rapidement résumé la conférence dans ce billet.
Les fichiers polyglottes sont des fichiers qui apparaissent comme étant d'un certain type (exemple : un fichier PDF), mais qui pourtant seront interprétés différement si on les ouvre dans un autre programme.
Par exemple, nous allons voir dans cet article comment créer un binaire ELF (exécutable Linux) qui contiendra également un PDF, une archive Jar (exécutable Java) et du code Html. Par contre, pour éviter que vous regardiez seulement comment qu'on fait sans lire les explications que j'aurais écrit avec patience juste pour vous, et ben je mettrais les lignes de commandes tout en bas de l'article! (Rassurez-vous, pour les plus pressés, vous pouvez toujours scroller ;-) ).
Voici l'architecture du fichier polyglotte que l'on va créer :
- Binaire ELF
- Archive Jar
- HTML
Et vous verrez que même si on n'a qu'un seul gros fichier, il est tout à fait possible d'ouvrir chacun des fichiers qu'il contient! Pour comprendre comment ça marche, il faut regarder un peu mieux l'organisation des formats de fichiers utilisés.
Les binaires ELF (si je ne me plante pas) doivent impérativement débuter par l'en-tête ELF, puis doit contenir toutes les instructions à exécuter. Les instructions s'exécutant "séquentiellement" suivant les appels à celles-ci, le programme va finalement s'arrêter à une instruction de type "EXIT" (c'est du pseudo-code, pas de l'ASM :P). Du coup, on peut bien mettre ce qu'on veut après, tant que le programme n'essaye pas d'exécuter ça comme des fonctions, ça devrait passer.
Le PDF est organisé comme l'ELF. Il doit (théoriquement) débuter par une signature PDF (sous la forme %PDF-X.Y
). En pratique, tant que cette signature est localisée dans les 1024 premiers octects du fichier PDF, la plupart des visionneuses PDF ouvrent les fichiers sans problème. Donc, tant que notre binaire ELF ne fait pas plus d'1ko, en mettant un PDF après ça marche pas mal. Si vous vous demandez comment on détecte la fin d'un PDF (et vous avez raison de le faire), on peut remarquer que les fichiers se terminent par %%EOF
.
Du coup, il nous reste à mettre après notre ELF et notre PDF une archive Jar qui contient elle-même du HTML.
Une page Html, c'est quoi ? Et bien je vais vous dire ce que c'est. C'est du texte qui commence par <html>
et qui fini par </html>
. Donc tout ce qui se trouve entre ces deux balises sera interprété par les navigateurs. Même si ces balises sont situés après 28Mo de pur binaire, ça fonctionnera.
Une archive Jar, ce n'est rien de plus qu'une archive Zip qui contient tous les fichiers .class
Java ainsi qu'un fichier MANIFEST
. Ce Jar doit impérativement se terminer à la fin du fichier. On peut quand même noter deux choses supplémentaires sur l'archive Jar :
Les fichiers Class Java contiennent toutes les chaînes de caractères en clair. C'est à dire qu'en parcourant le fichier binaire, on pourra quand même lire les chaînes de type String
de notre code Java. C'est cette particularité que nous allons utiliser pour intégrer notre code Html au code Java. Le navigateur tombera à un moment sur ces balises html et affichera le code interprété. Toutefois, on peut aussi placer notre code Html à n'importe quel endroit du fichier polyglotte, et pas nécéssairement dans le code Java. Je l'ai fait ici simplement pour ajouter un niveau de "difficulté" ;)
Le problème c'est que nos classes Java sont regroupées dans une archive Zip. Le Zip, je ne sais pas si vous le savez, mais il peut être compressé, ou non. S'il est compressé, on ne pourra pas accéder à la chaîne Html en clair, mais si on désactive la compression, notre code Html sera pleinement accessible.
Pour résumer :
- Le ELF doit être au début du fichier
- Le PDF doit commencer dans les 1024 premiers octets du fichier
- Le code Html peut être inclut n'importe où dans le fichier. Dans notre cas, on le mettra comme variable
String
d'une des classes Java. On poussera même le vice en mettant un bout de Javascript dans le Html ;) - L'archive Jar ne doit pas être compressée et doit terminer le fichier.
On remarque que toutes ces manipulations sont possibles pour deux raisons :
- Les formats de fichiers sont plutôt permissifs
- Les lecteurs de fichiers sont assez laxistes avec les formats et tolèrent que le code actif ne commence et ne termine pas le fichier effectivement lu.
On peut ensuite imaginer plein d'applications à ce type de fichiers. La plupart des anti-virus doivent détecter rapidement si un fichier est infecté ou non. Du coup, bien souvent, si le fichier semble être un PDF, il n'est analysé que comme un PDF. S'il possède également du code binaire ou du Javascript malicieux, il ne sera pas analysé comme tel.
Je sais que vous en avez envie, donc passons à la pratique!
On a deux façons de créer notre fichier polyglotte : écrire chacun des 3 fichiers à la main en assembleur/binaire, tel que le fait Ange Albertini, ou bien à l'arrache comme je l'ai fait moi, de la manière suivante :
Commençons par créer un petit binaire tout simple à partir d'un code écrit en C, qui va simplement afficher un texte à l'écran.
#include <stdio.h> int main(void){ printf("quackiNuX [elf]\\n"); return 0; }
On compile :
gcc -Wall quackiNuX.c -o quackiNuX.elf
Le fichier PDF est réalisé simplement depuis Libre Office. Une ligne de texte, et on exporte en PDF.
Le code source Java est identique au code C, on y rajoute simplement une variable globale contenant le code Html :
public class QuackiNuX{ private static final String h = "<html><body><style>body { visibility: hidden; } .n { visibility: visible; position: absolute; padding: 0 1ex 0 1ex; margin: 0; top: 0; left: 0; }</style><div class=n><h1>quackiNuX [Html inside Java]</h1><script>alert('quackiNuX [Javascript inside Html inside Java]');</script></div><!--"; public static void main(String[] args){ System.out.println("quackiNuX [Jar]"); } }
La compilation et la création du Jar :
javac QuackiNuX.java -d java cd java jar cvmf0 MANIFEST.MF ../quackiNuX.jar *.class
Enfin, pour créer notre fichier polyglotte, on concatène tous les fichiers à la suite les uns des autres :
$ cat quackiNuX.elf quackiNuX.pdf quackiNuX.jar > mix/quackiNuX.mix $ cd mix/ $ ls quackiNuX.mix $ cp quackiNuX.mix{,.jar} $ cp quackiNuX.mix{,.pdf} $ cp quackiNuX.mix{,.html} $ ll total 128 -rwxrw-r-- 1 quack quack 22328 juin 27 22:06 quackiNuX.mix -rwxrw-r-- 1 quack quack 22328 juin 27 22:06 quackiNuX.mix.html -rwxrw-r-- 1 quack quack 22328 juin 27 22:06 quackiNuX.mix.jar -rwxrw-r-- 1 quack quack 22328 juin 27 22:07 quackiNuX.mix.pdf $ md5sum * 402fa683789e4b06dc42943d929cb24f quackiNuX.mix 402fa683789e4b06dc42943d929cb24f quackiNuX.mix.html 402fa683789e4b06dc42943d929cb24f quackiNuX.mix.jar 402fa683789e4b06dc42943d929cb24f quackiNuX.mix.pdf
Les 4 fichiers sont identiques, et pourtant si on les ouvre tous à la fois, on obtient ceci :
#WIN
Comme vous pouvez le voir ici, faire un fichier polyglotte ça a l'air compliqué de premier abord, mais étant donné le laxisme des formats et lecteurs, un simple cat
sur 3-4 fichiers permet d'en créer un qui marche! :)
Special thanks to Ange Albertini and his presentation at SSTIC 2013