Solution du challenge d'inforensique proposé par fargoth sur NewFFR

Introduction

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 . Liens UndeadLink ici et .
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

Précautions pré-analyse

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 :)

Analyse de la partition home

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 :
[ Série d'images type cartoon ]
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).

Les emails

Les mails présents sous .chpowa-mail sont ceux qui nous donnent le plus d'informations pour notre mission.

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 :
[ Photo d'un pont de San Francisco ]

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 :
[ Photo de Los Angeles de nuit ]

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.

Analyse rapide de la capture réseau

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

Casser la communication chiffrée

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 :

  1. Créer depuis Wireshark un nouveau fichier pcap en créant un filtre sur l'adresse IP communiquée dans le message stéganographié (ip.addr eq 62.147.108.217)
  2. Depuis cette capture allégée, créer deux nouvelles captures, l'une filtrant sur le poste de Delafourchette comme source, l'autre sur la machine de Trébuchet comme source.
  3. Pour chaque capture obtenue, faire un "follow TCP" puis une exportation "RAW"

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

Adresses IP des protagonistes

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

No place like 127.0.0.1

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