Fin juillet 2009, fargoth en invoquait à l'esprit hacker via sa prose sur NewFFR :
Hola !
Durant ces derniers jours, j'ai concocté un petit défi mélangeant Linux, reverse, crypto et un peu de prog. Je viens donc faire un peu de pub ici.
Dans ce défi, vous incarner un "expert" en informatique forensique chargé de prouver qu'un employé d'une entreprise revend des informations aux concurrents. Vous aurez accès à une capture réseau ainsi qu'une image du disque dur de cet employé. J'ai également prévu une sorte de classement en fonction des indices découverts, plus l'indice est difficile à trouver plus il rapportera de points. Je ne fournis pas la liste des indices à trouver pour éviter de "donner la réponse" au challenge mais lorsque vous m'envoyer ce que vous avez trouvé, je vous indiquerai si vous avez passé à coté d'un indice rapportant des points.
Pour le challenge, le readme et le classement, c'est par ici :
Forensic Challenge #1
L'archive fait quand même 70 MB et 145 MB une fois décompréssée, donc prévoyez un peu de place.
Les premiers points sont assez facile à obtenir et si vous bloquer n'hésiter pas à me demander un petit indice ;-)
Bonne chance,
fargoth
Un raison de la taille des fichiers fournis pour le challenge, nous n'avons pas pu les inclure dans le zine mais vous pourrez obtenir l'image disque recompressée en XZ ici et la trace réseau là. Liens UndeadLink ici et là.
Parmi les fichiers mis à disposition on avait l'introduction suivante qui nous dressait direct le décor :)
Mise en situation ----------------- Vous êtes Gilbert Descloux, expert dans le domaine de l'informatique forensic. La société Chaussette Powaaa SA, un des leaders mondiaux sur le marché de la chaussette, a fait appel à vos services. Apparemment, ils suspectent un de leurs employés de vendre des informations à la concurrence. Voici le mail que le responsable informatique de Chaussette Powaaa SA vous a envoyé : -------------------------------------------------------------------------------- Subject: Demande d'analyse concernant le poste 042 From: Raoul Jugnot <raoul.jugnot@chaussette-powaaa.com> Date: Thu, 29 Jul 2009 14:44:36 +0200 To: Gilbert Descloux <gilbert.descloux@hotmail.com> Monsieur Descloux, Suite à nos précédents mails, nous avons décidé de vous confier cette affaire. Nous suspectons l'utilisateur du poste 042 de fournir des informations à nos concurrents. C'est pourquoi, lundi, nous avons capturé le trafic réseau sortant et entrant de son poste de travail. Nous avons également effectué un backup de sa partition /home. Votre travail sera de déterminer si effectivement il fait sortir certaines informations de l'entreprise. Et si c'est le cas, trouvez à qui il a fournit quels informations et comment. Voici quelques informations concernant les fichier joints à ce mail : - L'employé utilise le poste 042 dont l'adresse IP est 192.168.101.42 - Nos machines tournent sur Linux Debian Lenny - Le système de fichier utilisé est l'ext3 - Nous utilisons un client mail propre à l'entreprise (chpowa-mailclient) - Les mails sont stockés au format EML dans le dossier .chpowa-mail En espérant que ces informations suffiront, je vous souhaite bonne chance. Tenez nous au courant de votre avancement. -- Raoul Jugnot Responsable informatique Chaussette Powaaa SA -------------------------------------------------------------------------------- Votre objectif -------------- Votre mission, si vous l'acceptez, sera d'aider ce pauvre Raoul. Il y a plus- ieurs informations clés à découvrir. Chaque information vaut un certain nombre de points en fonction de la difficulté à la trouver. Le but final est de savoir quels documents ont étés vendus et ce qu'ils contenaient. Pour ce faire vous disposez d'une trace pcap effectuée avec tcpdump et d'une image de la partition home faite avec la commande dd. Lorsque vous pensez avoir obtenu toutes les informations utiles ou que vous n'arrivez plus à en obtenir d'autres, envoyez moi un mail avec ces informations et votre nom ou pseudo. Je mettrai alors à jour votre score sur la page suivante http://membres.lycos.fr/stockage01/forensic_challenge_1.html Mon adresse e-mail : f a r g o t h {ateu} h o t m a i l {pouin} c o m Indiquez "Forensic Challenge #1" comme sujet svp. Bonne chance, fargoth
L'inforensique est un domaine pointilleux et si on veut faire comme les pros on doit suivre quelques règles. On procédera notamment à une copie des fichiers fournis et sauf cas particulier on travaillera sur des fichiers qu'on aura mis en lecture seule pour s'éviter de faire une fausse manip ou qu'un logiciel quelconque interfère sur notre analyse.
On fera calculera aussi une somme de contrôle de ces fichiers qui sera comparée à ceux obtenus lors de la fin de notre analyse pour être sûr que tout le processus a été parfaitement réalisé.
On obtiendra les hahs md5 suivants :
2de1bedb8946101c2c1f8f6ec56d2908 home_image
e934de24053456c1c622fe2c4dad87a7 readme.txt
d69ad7a79060f5894a3852d7cbcd8540 trace.pcap
Je précise aussi au passage que toute l'analyse s'est faite à l'aide d'outils libres et gratuits :)
L'image disque a été montée simplement avec la commande mount -o ro,loop home_image /mnt/.
Deux dossiers sont présents à la racine de cette image : lost+found (vide) et le dossier utilisateur de la personne suspectée : delafourchette.
On peut suspecter la personne d'avoir fait le ménage sur son espace disque car seul le dossier Desktop est visible, le reste des données se situe dans des dossiers cachés. Cela reste toutefois une supposition.
Les fichiers de configurations trouvés dans le dossier utilisateur révèle l'utilisation d'un environnement graphique GNOME avec l'utilisation d'applications GTK. On trouve en effet des dossiers .gnome, .gnome2, .gconf mais aucun dossier .kde ou .kde4.
De plus le contenu du fichier .dmrc est le suivant :
[Desktop] Session=gnome
Le fichier d'historique bash n'a pas été nettoyé de quelque façon que ce soit. Ce qui prouve que l'utilisateur n'a pas de connaissances particulières dans l'anti-forensics (ce qui joue en notre faveur).
Contenu du .bash_history :
chpowa-mailclient & cd /media/disk/ ./steghide --extract -sf San_Francisco_004.jpg -p Petite-Fleur-Des-Champs java -jar SecureTalk.jar & openssl enc -base64 -e -in /mnt/project-server/6E7F80C1/descriptif.txt ls -al rm steghide SecureTalk.jar message.txt San_Francisco_004.jpg
Cet historique met en évidence l'utilisation de points de montages divers (un serveur ainsi que très probablement une clé USB), l'utilisation d'un logiciel de stéganographie (steghide) , l'utilisation d'un logiciel en Java, le chiffrement en base64 d'un fichier ainsi que la suppression de fichiers.
Un fichier nommé .recently-used.xbel est présent dans le dossier utilisateur et est utilisé par GNOME pour garder en mémoire les derniers fichiers ouverts ainsi que les programmes utilisés pour les ouvrir.
La encore après recherche on apprend que l'existence de ce fichier est soumise à paramêtrage. L'utilisateur n'a pas pris la précaution de fouiller pour ses propres traces.
Tous les accès présents datent du 27 juillet 2009, à des heures précises et ont eu lieu sur ce qu'on présume être une clé USB :
file:///media/disk/02%20-%20My%20Name%20Is.ogg avec VLC à 14:00:37
file:///media/disk/message.txt avec gedit à 14:02:55
file:///media/disk/04%20-%20Still%20D.R.E.%20(feat.%20Snoop%20Dogg).ogg avec VLC à 14:07:51
file:///media/disk/08%20-%20The%20Real%20Slim%20Shady.ogg avec VLC à 14:12:44
file:///media/disk/10%20-%20Forgot%20About%20Dre%20(feat.%20Eminem).ogg avec VLC à 14:37:45
Le fichier .xsession-errors contient des logs de chargement de flux (principalement à destination de VLC) provoqués par le navigateur.
On trouve par exemple une playlist YouTube correspondant à une recherche sur Eli's Dirty Jokes, une série animée dont quelques images semblent avoir été chargées durant la navigation de l'utilisateur :
Le suspect semble aussi s'être rendu sur les sites www.vacancesdesiles.com et www.clubmed.com.
Le dossier .gnupg ne révèle rien d'intéressant ou plutôt l'absence de clé cryptographiques pour l'échange par courrier.
Les historiques présents dans .gnome2/epiphany montrent que l'utilisateur a effectué des recherches sur les fichiers sources.list de Debian (utilisés pour apt-get).
L'historique de GEdit (.gnome2/gedit-metadata.xml) montre l'ouverture d'un fichier message.txt (qui n'est plus présent car effacé d'après l'historique bash) :
<document uri="file:///media/disk/message.txt" atime="1248703382">
Le fichier .gconf/apps/evolution/mail/%gconf.xml contient la configuration mail de la boite jean.delafourchette@chaussette-powaaa.com par IMAP et SMTP (mots de passe non conservés).
Voici un mail suspect retrouvé dans INBOX :
Date: Thu, 23 Jul 2009 09:20:42 +0200 From: Gérard Pâquerette <gerard.paquerette@chaussette-powaaa.com> To: Jean Delafourchette <jean.delafourchette@chaussette-powaaa.com> Subject: L'heure du caté Ciao ! J'ai un truc de fou à te montrer ! Rdv dans 10 minutes devant la machine à café.
Difficile de déterminer si une intention malhonnète se cache derrière...
Voci un email prévenant d'une réunion :
Date: Fri, 24 Jul 2009 15:25:18 +0200 From: Bernard Dubosquet <bernard.dubosquet@chaussette-powaaa.com> To: Jean Delafourchette <jean.delafourchette@chaussette-powaaa.com> Subject: Réunion du 31 juillet Bonjour, Je vous rappelle que vendredi prochain à 09h00 se tiendra notre réunion visant à déterminer la stratégie à adopter concernant la promotion de notre collection de chaussettes hiver 2009-2010 Cordialement,
Il y a aussi un mail conernant une fête pour le départ d'une autre employée que notre suspect ne semble pas tenir dans son coeur (mail dans SENT) :
From: Jean Delafourchette <jean.delafourchette@chaussette-powaaa.com> To: Nadine Dutoit <nadine.dutoit@chaussette-powaaa.com> Date: Wed, 22 Jul 2009 13:53:56 +0200 Subject: Re: Fête de départ pour Josette Josette c'est qu'une cruche. Comptez pas sur moi pour mettre le moindre centime pour cette vielle chouette. Vivement la fin du mois et bon débarras.
Enfin dans le dossier TRASH on trouve un mail en provenance d'un contact extérieur :
Date: Mon, 27 Jul 2009 13:21:22 +0200 From: Hubert Trébuchet <hubert.trebuchet@free.fr> To: Jean Delafourchette <jean.delafourchette@chaussette-powaaa.com> Subject: Photo de vacances Salut Jean ! Voilà la photo dont je t'avais parlé la dernière fois. Bonne semaine, Hubert Content-Type: image/jpeg; name="San_Francisco_004.jpg" Content-Description: San_Francisco_004.jpg Content-Disposition: attachment; filename="San_Francisco_004.jpg"; creation-date="Mon, 27 Jul 2009 10:19:23 +0200"; modification-date="Mon, 27 Jul 2009 10:19:23 +0200" Content-Transfer-Encoding: base64
S'en suit bien sûr l'image encodée en base64.
Pour l'extraire, une copie du mail a été faite, les headers ont été retirés puis a été rajouté au début la ligne "begin-base64 644 prout" ainsi qu'une ligne finale "===="
L'extraction s'est ensuite faite par la commande :
uudecode -o out.jpg Photo\ de\ vacances.eml
On obtient alors la photo suivante :
En reproduisant la commande exécutée par l'utilisateur (steghide --extract -sf out.jpg -p Petite-Fleur-Des-Champs) on retrouve le contenu du fichier message.txt :
Monsieur Delafourchette, L'échange se fera aujourd'hui (28 juillet 2009) à 16h30 précisément (heure UTC + 2). Le document qui nous intéresse est le descriptif du projet numéro 742. Utilisez le programme SecureTalk que je vous avais fournis afin de m'envoyer le document. Pour le lancer utilisez la commande suivante : java -jar SecureTalk.jar Voici l'IP à laquelle vous vous connecterez : 62.147.108.217 Une fois l'envoi effectué, n'oubliez surtout pas de supprimer le programme SecureTalk, la photo ainsi que ce texte. Supprimez également l'e-mail. Soyez à l'heure, Hubert Trébuchet
On a donc la preuve d'une communication entre une personne extérieure et le suspect concernant la transmission de données confidentielles.
En effectuant une recherche sur le nom trebuchet sur l'image de la partition, on retrouve quelques occurences. grep -b -a trebuchet home_image nous donne les offsets où se trouve le mot trebuchet
hexdump -C -s <offset> -n 500 home_image nous affiche les 500 octets à partir de cet offset.
Ensuite il faut fonctionner par dychotomie pour obtenir l'offset exact et la longueur des données à extraire.
Exemple avec la commande suivante
dd if=home_image of=mail.txt count=648206 bs=1 skip=77595648
qui nous a permis d'obtenir le message suivant :
Date: Thu, 23 Jul 2009 15:16:36 +0200 From: Hubert Trébuchet <hubert.trebuchet@free.fr> To: Jean Delafourchette <jean.delafourchette@chaussette-powaaa.com> Subject: Photo de vacances Salut Jean ! Je suis de retour de Californie. Je t'ai joint une petite photo et je vais t'en envoyer une autre dans quelques jours. A une prochaine, Hubert Content-Type: image/jpeg; name="Los_Angeles_008.jpg" Content-Description: Los_Angeles_008.jpg Content-Disposition: attachment; filename="Los_Angeles_008.jpg"; creation-date="Thu, 23 Jul 2009 13:34:26 +0200"; modification-date="Thu, 23 Jul 2009 13:34:26 +0200" Content-Transfer-Encoding: base64
L'image jointe étant sur plusieurs blocks non consécutifs, ça récupération est problématique : on parvient uniquement à obtenir une version endommagée.
Une recherche sur l'image disque "742" nous indique que le fichier convointé par la concurrence est le fichier file:///mnt/project-server/project-742/projet-742-descriptif.txt.
Si l'on souhaite obtenir plus de preuves, il nous faut cette photo de Los Angeles. Aditionnemment une recherche des fichiers jar sur le disque (format PKZip) avec des outils comme SleuthKit et PhotoRec s'est montrée infructueuse...
On va donc devoir avoir recourt à un outil plus ext3-aware qui s'appelle ext3grep qui se définie comme "A tool to investigate an ext3 file system for deleted content and possibly recover it.".
Comme pour le SleuthKit, il faut passer au logiciel les inodes que l'on souhaite étudier. Sous Linux, l'inode de la racine est toujours de 2. C'est par là que l'on va commencer ;-)
> ext3grep --inode 2 --ls home_image Running ext3grep version 0.10.1 WARNING: I don't know what EXT3_FEATURE_COMPAT_EXT_ATTR is. Number of groups: 16 Loading group metadata... done Minimum / maximum journal block: 49407 / 53520 Loading journal descriptors... sorting... done The oldest inode block that is still in the journal, appears to be from 1248702602 = Mon Jul 27 15:50:02 2009 Number of descriptors in journal: 2887; min / max sequence numbers: 13 / 394 Inode is Allocated Loading home_image.ext3grep.stage2.... done The first block of the directory is 513. Inode 2 is directory "". Directory block 513: .-- File type in dir_entry (r=regular file, d=directory, l=symlink) | .-- D: Deleted ; R: Reallocated Indx Next | Inode | Deletion time Mode File name ==========+==========+----------------data-from-inode------+-----------+========= 0 1 d 2 drwxr-xr-x . 1 2 d 2 drwxr-xr-x .. 2 4 d 11 drwx------ lost+found 4 end d 18145 drwxr-xr-x delafourchette
Il suffit ensuite de répéter la commande avec une autre inode :
The first block of the directory is 75265. Inode 18145 is directory "delafourchette". Directory block 75265: .-- File type in dir_entry (r=regular file, d=directory, l=symlink) | .-- D: Deleted ; R: Reallocated Indx Next | Inode | Deletion time Mode File name ==========+==========+----------------data-from-inode------+-----------+========= 0 1 d 18145 drwxr-xr-x . 1 2 d 2 drwxr-xr-x .. 2 3 d 18146 drwxr-xr-x Desktop 3 4 d 18147 drwxr-xr-x .chpowa-mail 4 5 d 18161 drwx------ .config 5 6 d 18166 drwx------ .dbus 6 7 d 18169 drwx------ .gconf 7 8 d 18300 drwx------ .gconfd 8 9 d 20201 drwxr-xr-x .gnome 9 10 d 20204 drwx------ .gnome2 10 11 d 18302 drwx------ .gnome2_private 11 12 d 18303 drwx------ .gnupg 12 13 d 18308 drwxr-xr-x .gstreamer-0.10 13 14 d 20261 drwx------ .local 14 15 d 20283 drwx------ .metacity 15 16 d 20317 drwx------ .mozilla 16 17 d 20320 drwxr-xr-x .nautilus 17 18 d 20334 drwx------ .ssh 18 19 d 20335 drwx------ .thumbnails 19 20 r 18310 rrw-r--r-- .bash_logout 20 21 r 18311 rrw-r--r-- .bashrc 21 22 r 18318 rrw------- .dmrc 22 23 r 18313 rrw-r----- .gksu.lock 23 24 r 18314 rrw------- .ICEauthority 24 26 r 18315 rrw-r--r-- .profile 25 26 r 18316 D 1248705811 Mon Jul 27 16:43:31 2009 rrw------- .Xauthority 26 28 r 18317 rrw-r--r-- .xsession-errors 27 28 r 18312 D 1248705811 Mon Jul 27 16:43:31 2009 rrw-r----- .vboxclient-clipboard.pid 28 29 d 26209 drwxr-xr-x .vlc 29 31 r 18247 rrw------- .bash_history 30 31 r 18320 D 1248705811 Mon Jul 27 16:43:31 2009 rrw-r----- .vboxclient-seamless.pid 31 end r 18239 rrw-r--r-- .recently-used.xbel
Les inodes supprimées sont marquées de la lettre D. On peut alors continuer à fouiller par inode ou utiliser la commande ext3grep --dump-names pour obtenir une liste complète des fichiers présents (même ceux supprimés).
La commande ext3grep --restore-file "delafourchette/.chpowa-mail/TRASH/Vacances en Californie.eml" home_image nous permettra d'obtenir une copie valide du mail qui a été supprimé :)
Le fichier eml extrait est ici.
L'image jointe au fichier est la suivante :
Une extraction similaire à la dernière fois (steghide --extract -sf out.jpg -p Petite-Fleur-Des-Champs) nous permet d'obtenir une archive file.tar.bz2 qui contient le fichier info.txt que voici :
Monsieur Delafourchette, Nous nous réjouissons de pouvoir faire affaire avec vous. Nous sommes actuellement particulièrement intéressés par l'un des projets de votre entreprise et nous avons besoin de votre aide afin de nous le procurer de manière la plus discrète possible. Nous vous indiquerons quels fichiers nous intéressent le jour de la transaction. Vous utiliserez le programme fournis dans cette archive afin de nous envoyer les documents. Ce programme nous permettra de discuter et d'échanger des fichiers que vous aurez préalablement encodé en base64, et ce de manière cryptée afin de ne laisser aucune preuve. L'adresse IP à laquelle vous connecter vous sera fournie en même temps que les autres informations. Vous devrez bien entendu supprimer tous ces fichiers une fois la transaction effectuée. Essayez également de travailler un maximum sur une clé USB afin de ne pas laisser de trace sur le disque dur de votre poste. Les détails exacts vous seront transmis fin de la semaine ou début de la semaine prochaine. Hubert Trébuchet
Et une archive Java (fichier jar) nommée SecureTalk.jar.
Beaucoup de paquets sont présents dans cette capture, principalement dus au visionnage de vidéos sur YouTube où le téléchargement d'un archive .tar.bz2 du logiciel PHP.
Le navigateur de l'utilisateur est ainsi identifié :
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020409 Iceweasel/3.0.6 (Debian-3.0.6-1)
La communication illégale avec l'IP 62.147.108.217 (tel que vu précédemment) commence au paquet 22982 et prend fin au 23040. Le port destination est le 3581 (TCP).
Le paquet 23020 envoyé vers le poste extérieur est plein dans le sens où il contient 1024 octets de donnés. Il est suivi par un paquet de 442 octets toujours dans le même sens de transmission. On pourrait donc envisager que le fichier transmis fait autour de 1466 octets.
Le chiffrement semble toutefois difficile à comprendre. On voit que des suites d'octets (par exemple de 4 octets) se répètent. Difficile d'imaginer une analyse statistique sachant qu'il s'agit d'un fichier .txt.
Dans le transfert sont aussi envoyés des mots clés Java ainsi que des entêtes (par exemple uq). Il est possible que les données transférées soient formatées selon un mécanisme de sérialisation propre à Java après avoir été chiffré.
Maintenant qu'on dispose du programme ayant servi pour les communications, on va le décortiquer et tenter de comprendre son fonctionnement dans le but d'obtenir les échanges en clair.
Une fois le fichier jar décompressé (c'est un simple fichier zip), on a recours à JAD pour décompiler les fichiers .class obtenus. La lecture des codes obtenus permet de découvrir rapidement que les instructions intéressantes se situent dans les fichiers network/NetworkManager.java, network/ReceiveThread.java, crypto/DiffieHellman.java et crypto/Blowfish.java.
Dans NetworkManager.java on voit que le client et le serveur s'envoient comme on s'en doutait des objets sérialisés par des flux de type ObjectInputStream et ObjectOutputStream. La simple création d'un ObjectInputStream provoque l'envoit d'un header spécial ACED0005 (hexa) qui permet aux applications de vérifier qu'elles discutent bien avec une autre application Java.
Une autre particilarité est que pour un objet on va retrouver 4, 5 voire peut-être 6 paquets envoyés sur le réseau.
Afin de travailler sur les paquets en mode offline, j'ai procédé de la façon suivante :
On nomme l'un des fichiers client2server.dat et l'autre server2client.dat :)
Soit le code suivant de NetworkManager.java extrait avec JAD (la gestion des erreurs a été retirée pour faire court) :
package network; import crypto.Blowfish; import crypto.DiffieHellman; import java.io.*; import java.math.BigInteger; import java.net.*; import javax.swing.JOptionPane; public class NetworkManager { public NetworkManager(MessageManager messMan) { isListening = false; isConnected = false; this.messMan = messMan; keySharing = new DiffieHellman(); } public boolean connectTo(String strIpAddress) { InetAddress address = null; address = InetAddress.getByName(strIpAddress); clientSocket = new Socket(address, 3581); inStream = new ObjectInputStream(clientSocket.getInputStream()); outStream.writeObject(keySharing.generateA()); BigInteger b = null; b = (BigInteger)inStream.readObject(); keySharing.setB(b); isConnected = true; encryptor = new Blowfish(keySharing.getKey()); connectThread = new ReceiveThread(messMan, inStream, encryptor); connectThread.start(); return true; } public boolean listen() { ServerSocket serverSocket = null; serverSocket = new ServerSocket(3581); clientSocket = serverSocket.accept(); outStream = new ObjectOutputStream(clientSocket.getOutputStream()); inStream = new ObjectInputStream(clientSocket.getInputStream()); BigInteger b = null; b = (BigInteger)inStream.readObject(); outStream.writeObject(keySharing.generateA()); keySharing.setB(b); isConnected = true; encryptor = new Blowfish(keySharing.getKey()); connectThread = new ReceiveThread(messMan, inStream, encryptor); connectThread.start(); return true; }
On voit côté client qu'un objet DiffieHellman "keySharing" est créé et qu'une donnée est envoyée par appel à generateA() est envoyée au serveur suite à quoi on recoit un BigInteger b du serveur qui permet après calcul de générer la clé de chiffrement utilisée dans le reste de la transaction.
De son côté le serveur fonctionne dans le sens inverse en recevant d'abord puis en envoyant une réponse. C'est le handhsake cryptographique que l'on doit casser pour obtenir la clé de chiffrement correspondant à keySharing.getKey().
Le contenu de DiffieHellman.java est le suivant :
package crypto; import java.math.BigInteger; import java.util.Random; public class DiffieHellman { public DiffieHellman() { p = new BigInteger("72549841864194078899726837116892585496955575260843302046062234899404431414511"); g = new BigInteger("58759714624708089702199189818787533437405834872094654299502596364496752316901"); } public BigInteger generateA() { rand = new Random(System.currentTimeMillis()); do a = new BigInteger(256, rand); while(a.compareTo(p) >= 0); return g.modPow(a, p); } public void setB(BigInteger b) { k = b.modPow(a, p); } public byte[] getKey() { byte retKey[] = new byte[16]; System.arraycopy(k.toByteArray(), 16, retKey, 0, 16); return retKey; } private Random rand; private BigInteger p; private BigInteger g; private BigInteger a; private BigInteger k; }
Ici on a 4 variables de type BigInteger : p, g, a et k. p et g sont hardcodés dans le code. k est l'entier que nous envoit le serveur et qui se trouve donc dans notre fichier server2client.dat.
Il ne nous reste plus qu'à trouver la variable a pour avoir de quoi retrouver la clé de chiffrement Blowfish :)
Or si on regarde le code, on voit que a est généré par Random(System.currentTimeMillis()). En informatique le hazard ou l'aléatoire n'existent pas. Une fonctione Random crachera inlassablement les même suites de chiffres pour peu qu'on lui donne toujours la même graine (seed) de départ.
Dans notre cas on connait plus ou moins cette graine puisque c'est la date exprimée en milliseconde du moment où Delafourchette a utilisé le programme soit aux alentours de 16h30 (d'après le message qui était stéganographié) le 27 juilet 2009 (d'après les timestamps des fichiers).
Il nous suffit donc de bruteforcer cette variable en prenant comme fourchette la date du 27/07/2009 de 16h28 à 16h32. L'opération de calcul est assez importante puisque la fonction modPow calcule des exponentiels et des modules sur de gros entiers et il y a beaucoup de millisecondes sur 4 minutes mais avec un ordinateur de notre époque (entre 1 et 2Ghz de proc) c'est l'affaire de quelques minutes.
Dans le pire des cas, en imaginant qu'il y ait un souci de zone horaire dans les fonctions Java, on peut prendre une fourchette de -12h/+12h pour couvrir l'ensemble des fuseaux.
Le code suivant va effectuer le brute force :
import java.io.ObjectInputStream; import java.io.FileInputStream; import java.io.IOException; import java.math.BigInteger; import java.util.GregorianCalendar; import java.util.Date; import java.util.Random; public class BruteForce { public BruteForce() { } public static void main(String args[]) throws IOException, ClassNotFoundException { FileInputStream fis = new FileInputStream("client2server.dat"); ObjectInputStream ois = new ObjectInputStream(fis); BigInteger plop = (BigInteger) ois.readObject(); // keySharing.generateA() ois.close(); fis.close(); System.out.println("BingInteger from stream"); System.out.println(plop.toString()); BigInteger p = new BigInteger("72549841864194078899726837116892585496955575260843302046062234899404431414511"); BigInteger g = new BigInteger("58759714624708089702199189818787533437405834872094654299502596364496752316901"); GregorianCalendar gc1 = new GregorianCalendar(2009, 06, 27, 16, 28, 0); GregorianCalendar gc2 = new GregorianCalendar(2009, 06, 27, 16, 32, 0); long l1 = gc1.getTimeInMillis(); long l2 = gc2.getTimeInMillis(); System.out.println(l1+" => "+l2); int ok = 0; while(1==1) { BigInteger x = new BigInteger(256,new Random(l1)); if(plop.compareTo(g.modPow(x, p))==0) { System.out.println("Trouve: "+l1); // == 1248705015814 == Mon Jul 27 16:30:15 CEST 2009 :) break; } if(l1 >= l2) { System.out.println("End"); break; } System.out.println(l1+"++"); l1++; } } }
La valeur bruteforcée est rapidement trouvée et correspond à 1248705015814 soit la date du 27/07/2009 à 10h30 et 15 secondes.
NB : Les objets GregorianCalendar comptent les mois à partir de 0 d'où le 06 pour le mois de juillet.
La ligne 20 obtient la donnée transférée sur le réseau, la ligne 39 effectue le calcul à partir des variables et de la valeur bruteforcée et compare les résultats.
On peut alors calculer la clé Blowfish et procéder au déchiffrement de la communication (code ici) :
import java.io.ObjectInputStream; import java.io.FileInputStream; import java.io.IOException; import java.math.BigInteger; import java.util.Random; import crypto.Blowfish; public class GetKey { public GetKey() { } // fonction pompee sur le web pour affichage hexa public static String getHexString(byte[] b) throws Exception { String result = ""; for (int i=0; i < b.length; i++) { result +="\\x"; result += Integer.toString( ( b[i] & 0xff ) + 0x100, 16).substring( 1 ); } return result; } // the big one public static void main(String args[]) throws IOException, ClassNotFoundException, java.lang.Exception { // chargement des donnnees du client a destination du serveur FileInputStream fis = new FileInputStream("client2server.dat"); ObjectInputStream ois = new ObjectInputStream(fis); // Lecture BigInteger BigInteger cli = (BigInteger) ois.readObject(); // keySharing.generateA() System.out.println("BingInteger from Client"); System.out.println(cli.toString()); // chargement des donnees du serveur a destination du client FileInputStream fis2 = new FileInputStream("server2client.dat"); ObjectInputStream ois2 = new ObjectInputStream(fis2); // Lecture BigInteger BigInteger srv = (BigInteger) ois2.readObject(); // keySharing.generateA() System.out.println("BingInteger from Server"); System.out.println(cli.toString()); BigInteger p = new BigInteger("72549841864194078899726837116892585496955575260843302046062234899404431414511"); BigInteger g = new BigInteger("58759714624708089702199189818787533437405834872094654299502596364496752316901"); BigInteger x = new BigInteger(256,new Random(1248705015814L)); // == 1248705015814 == Mon Jul 27 16:30:15 CEST 2009 :) // si pK == srv => echange ok BigInteger pK = g.modPow(x, p); System.out.println("PKey"); System.out.println(pK.toString()); BigInteger sK = srv.modPow(x, p); System.out.println("Temp Key"); System.out.println(sK.toString()); System.out.println(getHexString(sK.toByteArray())); byte retKey[] = new byte[16]; System.arraycopy(sK.toByteArray(), 16, retKey, 0, 16); System.out.println("Blowfish Key"); System.out.println(getHexString(retKey)); Blowfish encryptor = new Blowfish(retKey); byte cryptedMessage[]; System.out.println("== Donnees envoyees par le client =="); try { while((cryptedMessage = (byte[])ois.readObject()) != null) System.out.println(new String(encryptor.decrypt(cryptedMessage), "UTF8")); } catch(ClassNotFoundException e) { e.printStackTrace(); } catch(java.io.EOFException e) { } System.out.println("== Donnees envoyees par le serveur =="); try { while((cryptedMessage = (byte[])ois2.readObject()) != null) System.out.println(new String(encryptor.decrypt(cryptedMessage), "UTF8")); } catch(ClassNotFoundException e) { e.printStackTrace(); } catch(java.io.EOFException e) { } ois.close(); fis.close(); ois2.close(); fis2.close(); } }
Ce qui nous donne le résultat suivant :
BingInteger from Client 25140003318008955322601236051866126892541823954308285918419524882993158040412 BingInteger from Server 25140003318008955322601236051866126892541823954308285918419524882993158040412 PKey 25140003318008955322601236051866126892541823954308285918419524882993158040412 Temp Key 6517437855449045348994765524914728530525814314271743246717642203703097704967 \x0e\x68\xbd\x35\xcd\x32\x24\x72\x40\x1b\x68\x51\x1c\x14\x85\x9e\x49\x9d\x9b\xc1\xf8\x6b\x1c\xaa\xf7\x33\xfc\x43\xac\x68\x42\x07 Blowfish Key \x49\x9d\x9b\xc1\xf8\x6b\x1c\xaa\xf7\x33\xfc\x43\xac\x68\x42\x07 == Donnees envoyees par le client == Bonjour Monsieur Trébuchet Oui, le voici Ky0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t LS0tLS0tLS0tLS0tLS0tLSsKfCAgTsKwIGRlIHByb2pldCAgOiA3NDIgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgIE5vbSBkZSBw cm9qZXQgOiBMYSBCbGluZ2JsaW5nIFNvY2tldCBDaHJpc3RtYXMgZWRpdGlvbiAy MDA5ICB8CistLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rCgpDb3VydGUgZGVzY3JpcHRpb24gOgot LS0tLS0tLS0tLS0tLS0tLS0tLQoKTGEgQmxpbmdibGluZyBTb2NrZXQgQ2hyaXN0 bWFzIGVkaXRpb24gMjAwOSByZXByZW5kIGxlIHByaW5jaXBlCmRlIGxhIHZlcnNp b24gMjAwOCBtYWlzIGVuIGVuY29yZSBwbHVzIGJsaW5nYmxpbmcuIExhIGNoYXVz c2V0dGUKc2VyYSByb3VnZSBhdmVjIGRlcyBwYWlsbGV0dGVzIGRvcsOpZXMuIEVs bGUgY29tcG9ydGVyYSBkZXV4CmNsb2NoZXR0ZXMgc3VyIGNoYWN1biBkZXMgY290 w6lzIGFpbnNpIHF1J3VuIGdyZWxvdCBheWFudApsJ2FwcGFyZW5jZSBkJ3VuZSBi b3VsZSDDoCBmYWNldHRlIMOgIGxhIHBvaW50ZSBkdSBwaWVkLgoKClNjaMOpbWE6 Ci0tLS0tLS0KCiAgICAgICArLS0tdnYtLS0rCiAgICAgICB8ICogfHwgKiB8CiAg ICAgICB8KiAgfHwqICB8CiAgICAgICB8ICAgfHwgICB8CiAgICAgICB8ICAuwrRg LiAgfCAgICAgICAgICAgICAgICBfXwogICAgICAgfCAgfDAwfCAqfCAgICAgICAg ICAgICAgIC9cL1wKICAgICAgIHwgKmAuLsK0KiB8ICAgICAgICAgICAgICB8XC9c L3wKICAgICAgIHwqICAgICogICBcX19fX19fX19fX19fX19cXC8vCiAgICAgICB8 ICAgICogICAgKiAgICAqICAgICogICAgKiAgIGAuCiAgICAgICB8ICAgKiAgICAq ICAgICogICAgKiAgICAqICAgICp8CiAgICAgICB8ICAqICAgICogICAgKiAgICAq ICAgICogICAgKiB8CiAgICAgICBcX19fX19fX19fX19fX19fX19fX19fX19fX19f Xy7CtAoKICBMYSBCbGluZ2JsaW5nIHNvY2tldCBDaHJpc3RtYXMgZWRpdGlvbiAy MDA5Cg== C'est entendu. Ravis d'avoir fait affaire avec vous. Oui, ne vous en faites pas. Aurevoir == Donnees envoyees par le serveur == Bonjour Monsieur Delafourchette Avez vous le document que je vous ai demandé ? Merci à vous, le virement sera effectué comme convenu sur votre compte une fois que nous aurons vérifié la validité de ces informations. De même. N'oubliez pas de supprimer tous les fichiers compromettants. Aurevoir
Quand au fichier transféré, ce dernier a été encodé en base64 avec openssl pour être inclus dans la discussion. Si on le décode on obtient ce texte :
+---------------------------------------------------------------+ | N° de projet : 742 | | Nom de projet : La Blingbling Socket Christmas edition 2009 | +---------------------------------------------------------------+ Courte description : -------------------- La Blingbling Socket Christmas edition 2009 reprend le principe de la version 2008 mais en encore plus blingbling. La chaussette sera rouge avec des paillettes dorées. Elle comportera deux clochettes sur chacun des cotés ainsi qu'un grelot ayant l'apparence d'une boule à facette à la pointe du pied. Schéma: ------- +---vv---+ | * || * | |* ||* | | || | | .´`. | __ | |00| *| /\/\ | *`..´* | |\/\/| |* * \______________\\// | * * * * * `. | * * * * * *| | * * * * * * | \____________________________.´ La Blingbling socket Christmas edition 2009
L'adresse IP de M. Trébuchet est déjà connue, il s'agit de 62.147.108.217. Un whois -h whois.arin.net 62.147.108.217 nous renvoit :
inetnum: 62.147.79.0 - 62.147.255.255 netname: FR-PROXAD-DIALUP descr: Proxad / Free Telecom descr: Dynamic pool (dialup) descr: NCC#2002110278 (45312/45824) country: FR admin-c: ACP23-RIPE tech-c: TCP8-RIPE status: ASSIGNED PA mnt-by: PROXAD-MNT source: RIPE # Filtered
La personne est donc française et a Free.fr comme FAI.
L'adresse IP de M. Delafourchette (et par extension la société pour laquelle il travaille) peut se retrouver dans la capture réseau.
En effet au moment où il se connecte au site www.php.net, se site lui donne un cookie nommé COUNTRY qui est de la forme CC%2CXXX.XXX.XXX.XXX ou CC est le code du pays et XXX.XXX.XXX.XXX l'adresse IP du visiteur.
Dans le cas de M. Delafourchette, le cookie a pour valeur "COUNTRY=CHE%2C83.78.4.164".
L'entreprise est donc basée en Suisse. Son adresse IP sur le net est 83.78.4.164. Le whois donne les informations suivantes :
inetnum: 83.78.0.0 - 83.79.255.255 netname: BLUEWINNET descr: Bluewin is an LIR and ISP in Switzerland. descr: This range is used for dynamic customer pools. country: CH admin-c: BCR1-RIPE tech-c: BCR1-RIPE status: ASSIGNED PA remarks: In case of hack attacks, spam, scans etc. please remarks: send abuse notifications to abuse@bluewin.ch remarks: E-Mails to the persons below will be IGNORED! mnt-by: BLUEWINNET-MNT mnt-lower: BLUEWINNET-MNT source: RIPE # Filtered
L'entreprise a comme FAI Bluewin.net
Gilbert Descloux peut rentrer chez lui avec la satisfaction du travail terminé :p
On n'en dira pas autant de M. Delafourchette qui ne fera pas long feu dans son entreprise.
Retrouvez les codes, fichiers etc du challenge dans le dossier forensic dans data