La nuit du hack 2011 Préqual
April 5, 2011 in InfoSec
Dans le week-end du 2 au 3 mars 2011, j’ai participé aux qualifications de la nuit du hack. Sous le nom d’équipe lulz task force, nous étions 5 jeunes gaillards à l’assaut de 4 catégories de challenge : web, forensic, cryptographie et reverse.
Nous étions 5 au début mais on dira que nos effectifs se sont sérieusement émoussés au fil des heures et que, finalement, je me suis retrouvé seul à valider mes challenges. Malheureusement, un certain jb a planté son serveur Windows 2008 en voulant charger une base Active Directory et une certaine école d’ingénieurs (INSA) bloque des (enormement est un euphémisme) ports de son réseau à ses étudiants, ce qui réduit leur potentiel (hein seb
). Ce sont les dommages collatéraux du weekend ! Mention spéciale au wiki intégré de redmine qui permet facilement de synchroniser et de garder une trace de sa progression.
Chaque catégorie comporte 3 challenges qui vont crescendo en difficultés. Les défis webs étaient tous des challenges avec injection sql. Nous avons identifié tous les points d’injections mais malheureusement nous sommes des buses en ce qui concerne la rédaction des requêtes. On me souffle dans l’oreillette qu’il est possible de dumper les schémas de la base de données (ce qui rend les choses beaucoup plus faciles, thx dr. obvious). La forensic se résume à l’étude d’image de la ram. La cryptographie: pas de grosses surprises non plus mais là encore aucun succès. Pour le reverse engineering, il y avait une rom de nintendo DS à cracker et une application android que j’ai reverse
On en reparle plus bas.
Je vais décrire dans ce qui suit les techniques que j’ai employées pour résoudre les 3 challenges qui nous ont permis de finir 41eme (ce qui fait 550 points, le max étant 1200 sans compter les bonus). For lulz and glory. voir le classement
Dernière chose, si vous voulez vous aussi tester ce que je dis ou faire parler votre talent naturel (sisi) un mirroir des épreuves se trouve à cette adresse.
Forensic100 ou comment trouver un mot de passe de serveur VNC
Le but du jeu est de retrouver le mot de passe d’un serveur VNC (RealVNC). Pour cela, on nous fournit l’image de la ram de la machine sur laquelle tourne ce serveur. Etant un complet néophyte dans le domaine, je demande à mon Laurent préféré (le mec qui m’a fait aimer la discipline mais vous vous en foutez et je raconte ma vie comme je veux sur mon blog d’abord, meh) qui me conseille memorize.
Le soft est un freeware poussé par une grosse boite de forensic. L’outil permet de lister les processus ouvert et les fichiers associés et ainsi de découvrir les drivers qui tournent. Malheureusement il ne permet pas de dumper les fichiers ni de lire les clés de registres associées. Un bon outil qui fait rapidement la job (comme dirait ce Québecois de Laurent, non les français ne parlent pas comme ça), mais qui ne convient pas au problème.
En effet, j’ai installé entre temps un server RealVNC (la même version que listé par memorize cela dit, plutôt un bon point) pour regarder où le logiciel stockait son mot de passe. Et bien tout simplement dans la base de registre ! Chiffré par je ne sais quel algorithme (surement du DES).
Ayant constaté cela, la course va être facile. Je dump la base de registre de l’image mémoire et je vais lire la clé. Voilà de bien belles paroles mais je ne sais absolument pas faire ce genre de chose. C’est là que seb entend parler de volatility sur un site Grec (véridique). J’investigue la solution, compile le logiciel sur Windows (c’est du python) et je joue un peu avec. C’est de la ligne de commande. La communauté qui porte se logiciel a produit un certains nombre de plugins qui me seront utiles par la suite.
On commence l’épreuve à proprement dite maintenant (comme quoi l’adage réfléchir avant d’agir est toujours vrai:)).
On va utiliser volatility pour dumper des zones mémoires et récupérer ce qui nous intéresse. Pour cela nous allons utiliser les plugins volreg et volrip qui permettent de récupérer les informations systèmes de l’os en ram (je généralise un peu vite, il analyse du Windows XP, je n’ai aucune idée si cela marche avec autre chose que du Windows).
D:challengeVolatility-1.3_Beta>python volatility hivescan -f dump.raw Offset (hex) 44759904 0x2aafb60 44765192 0x2ab1008 47600264 0x2d65288 49462112 0x2f2bb60 57268056 0x369d758 117583880 0x7023008 117586784 0x7023b60 138480480 0x8410b60 140337160 0x85d6008 144967512 0x8a40758 145000296 0x8a48768 146788360 0x8bfd008 167239688 0x9f7e008
La première chose que vous remarquez, c’est que je travaille surWindows pour le coup
La seconde c’est que je dump une liste d’adresse mémoire qui ne font aucun sens. hivescan trouve “juste” les adresses occupées par le registre dans la RAM.
Ne nous arrêtons pas là:
D:challengeVolatility-1.3_Beta>python volatility hivelist -f dump.raw -o 0x2aafb60 Address Name 0xe1809008 Documents and SettingseleveLocal SettingsApplication DataMicrosoftWindowsUsrClass.dat 0xe1986008 Documents and SettingseleveNTUSER.DAT 0xe17a9768 Documents and SettingsLocalServiceLocal SettingsApplication DataMicrosoftWindowsUsrClass.dat 0xe179b758 Documents and SettingsLocalServiceNTUSER.DAT 0xe1770008 Documents and SettingsNetworkServiceLocal SettingsApplication DataMicrosoftWindowsUsrClass.dat 0xe175fb60 Documents and SettingsNetworkServiceNTUSER.DAT 0xe13ffb60 WINDOWSsystem32configsoftware 0xe14ab008 WINDOWSsystem32configdefault 0xe14abb60 WINDOWSsystem32configSAM 0xe14e4758 WINDOWSsystem32configSECURITY 0xe12e8288 [no name] 0xe1035b60 WINDOWSsystem32configsystem 0xe102e008 [no name]
A partir d’une adresse physique en mémoire, on récupère la liste des adresses virtuelles des emplacements du registre. Pour la peine volatility nous donne le nom des entrées ce qui va nous simplifier la vie.
J’avoue que la première chose que j’ai faite a été de dumper le fichier SAM même si cela ne sert à rien ici:
D:challengeVolatility-1.3_Beta>python volatility hashdump -f dump.raw -y 0xe1035b60 -s 0xe14abb60 Administrateur:500:bac14d04669ee1d1aad3b435b51404ee:fbbf55d0ef0e34d39593f55c5f2ca5f2::: Invité:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0::: HelpAssistant:1000:0f49d2f4d3c6fd9cdcf900189bc46b05:e9ee7219c4e84d50f2b5569b4f49a053::: SUPPORT_388945a0:1002:aad3b435b51404eeaad3b435b51404ee:23120f1b3baae60f657745ccecffd511::: eleve:1003:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
Seul le mot de passe Administrateur est tout de suite tombé. C’est “TOTO”. J’ai bien sûr utilisé john the ripper. Peut être que le mot de passe de élève était un flag bonus. Avis aux amateurs.
Revenons à nos moutons, et dumpons la base de registre “software”, là ou se situe l’entrée de VNC. Volatility va me permettre de dumper toute la base software avec la valeur des clés associées là où memorize me permettait seulement de voir la clé sans la valeur (et encore pas la base software car VNC se trouve à plusieurs endroits dans la base de registre).
python volatility hivedump -f dump.raw -i 0xe13ffb60 -v
L’option -v est très importante car elle permet de dumper les valeurs des clés. Sans elle, vous aurez juste les clés ce qui ne sert pas à grand chose dans notre cas. Je me retrouve avec un fichier nommé “0xe13ffb60.csv” qui est juste une base de registre
Je récupère dans la clé “Password” la valeur suivante : da6e31849577ad6b.
Je recherche 2 minutes un soft pour cracker une clé vnc. J’avoue que la technique de chiffrement de leur clé ne m’intéresse pas vraiment, j’aurai l’occasion d’écrire un brute force en Python plus tard
D:challengevncpwdump-win32-1_0_6>vncpwdump.exe -k da6e31849577ad6b VNCPwdump v.1.0.6 by patrik@cqure.net ------------------------------------- Password: secretpq
Le flag est donc secretpq. Voilà un premier challenge de validé ! J’ai bien dû mettre 4h pour faire ça.
Forensic300 ou parlez vous netcat ?
Même topo que précédemment. On nous donne seulement une image vmem qui est une image de la ram d’une machine virtuelle VMWare. Seul problème, volatility ne marche pas dessus. Pour le coup cela m’a un peu refroidi, je comptais mettre à profit l’expérience acquise sur le soft au challenge précédent pour résoudre rapidement celui-ci. Je me souviens ensuite des logiciels de forensic : foremost et Autopsy. Le premier est un file carver (récupère les fichiers de l’image) et le second un outil d’analyse de disque dur. Le second ne reconnait pas non plus l’image. Le premier récupère une série d’image dont un portrait dont le visage est flouté avec en surimpression un point d’interrogation. Le logiciel a également récupéré une vingtaine d’éxécutables. Ayant la grande flemme d’utiliser la commande “strings” dessus pour énumérer toute les chaines harcodées pour trouver un logiciel qui attire mon attention, je décide de procéder autrement (pour ceux qui se demandent, un fichier récupéré par foremost est composé uniquement de chiffres, probablement l’adresse en mémoire ou le fichier a été récupéré, rien d’excitant sauf pour les necrophages).
Je ressorts memorize qui lui contrairement à volatility récupère la liste des processus lancé sur la machine au moment de la prise du dump mémoire. On voit donc qu’un certain processus nommé “nc” (le petit nom de netcat) tourne sur la machine et connecté en sus à l’adresse secte.serverofdark_hamster.com et sur le port 48625. On avance à pas de géant. Memorize ne peut rien nous apprendre de plus mais l’on sait où chercher maintenant. Netcat étant un couteau suisse réseau, la commande relevée indique que netcat est connecté au serveur des hamsters sur le port indiqué. Seul problème : ce nom de domaine n’est pas résolu. Je pense tout de suite à trouver le fichier host mais sans succès. Dans un dernier sursaut (aka 30 minutes avant la fin du challenge):
D:challengeforensic300>strings DumpRAM_CTF.vmem | grep i -A 3 -B 3 hamster FILE0 FILE0 FILE0 secte.server_of_dark_hamster.com 88.190.230.12 +*Vt vAgzv -- ... --- Nnbf INTL secte server_of_dark_hamster test-PC MSFT 5.0 'si.com Secret pass is H4x0r rver_of_dark_hamster AleD @PyL @PyL
On affiche les trois lignes avant et après chaque occurrence de hamster dans la mémoire grâce à grep et à strings. On tombe sur deux choses intéressantes: un mot de passe et une ip. L’ip se trouve être en vérité le serveur du challenge. Je le scan avec nmap et en effet le port est bien ouvert.
A mon tour d’utiliser netcat:
D:challengeforensic300>nc 88.190.230.12 48625
J’initie de cette manière une connexion TCP entre moi et le server distant sur le port passé en argument. Fébrilement je rentre “H4x0r” comme mot de passe mais le serveur me coupe la connexion. Et là le doute s’immisce en moi. Mais je sais aussi que les organisateurs sont vicieux. Je tente donc à la place de “H4x0r” de rentrer le mot de passe : “Secret pass is H4x0r”.
deckard@Stephenson ~ $ nc 88.190.230.12 48625 Secret pass is H4x0r Nice job! The hash is 9vjgH368$hgHGjh
Note: je suis sous cygwin pour le coup.
Et bingo, le serveur répond un hash qui est le flag et qui me permet de marquer des points durement gagnés à la force du grep. Encore 4 heures de ma vie durement comblées.
RCE200 ou grossièretés et Android
Dernier challenge que j’ai résolu. On nous fournit juste un package d’une application Android. On peut lire à droite et à gauche sur la toile que le Java est un langage difficile à obfusquer et aisément décompilable.
Allons y !
Tout d’abord un apk est un fichier zip. On dézipe ça avec 7zip sans se poser de questions. On récupère ainsi plusieurs fichiers.
D:challengerce200rce200>ls -l total 430 -rw-r--r-- 1 deckard Administ 1420 Mar 29 13:29 AndroidManifest.xml drwxr-xr-x 2 deckard Administ 0 Apr 3 09:47 META-INF -rw-r--r-- 1 deckard Administ 4324 Mar 29 13:29 classes.dex drwxr-xr-x 7 deckard Administ 4096 Apr 3 09:40 res -rw-r--r-- 1 deckard Administ 1544 Mar 29 13:29 resources.arsc
META-INF et res sont des dossiers qui ne nous intéressent pas. Il y a dedans le certificat qui signe l’application et une image.
Les classes java sont contenues dans le fichier classes.dex (thx again dr. obvious, oh c’est bon hein !). A noter que j’ai essayé d’incorporer directement le projet dans eclipse mais cela n’est pas possible. C’est balot, j’aurai pu ainsi profiter du debugger ce qui aurait rendu la résolution du problème enfantine. Le fichier AndroidManifest.xml est un binaire (et non un xml). Eclipse ne peut donc pas l’importer.
Peu importe, je télécharge dex2jar qui va me donner un jar contenant les fichiers classes à partir du fichier dex. Là encore il ne s’agit que d’un fichier zip qui contient les classes java. Cela ne s’arrêtera donc jamais ?
Finalement on utilise le décompilateur Java DJ pour transformer les .class en .java. Pas vraiment besoin de jouer de la ligne de commande jusque là, ces logiciels possèdent une interface graphique (détail inutile mais qui explique le manque de coloration syntaxique).
Nous avons enfin des fichiers sources que nous pouvons incorporer dans Eclipse.
D:challengerce200rce200secretndhprequalsrce>ls -l total 976 D:challengeRCE200.srcndhprequalsrce>ls -l total 4 -rw-r--r-- 1 deckard Administ 1814 Apr 2 16:58 ReverseMe.java -rw-r--r-- 1 deckard Administ 2583 Apr 2 16:58 a.java -rw-r--r-- 1 deckard Administ 846 Apr 2 16:58 b.java -rw-r--r-- 1 deckard Administ 1335 Apr 2 16:58 c.java
Les choses étant bien faites pour les organisateurs, les fichiers ne compilent pas. J’ai bien réussi en réecrivant des sections de code à porter l’application sur le simulateur Android et à la faire marcher mais cela ne sert à rien à part tester si j’ai pu injecter des bugs dans le code (et en effet, ça déconne plein pot sic).
Une portion de code attire mon oeil dans le fichier c.java:
private static byte[] a = { 90, 5, 88, 88, 13, 13, 90, 90, 10, 4, 9,11, 93, 90, 11, 15, 93, 95, 5, 93, 5,8,8, 88, 90, 95, 9, 14, 90, 8,13, 94 };
private static byte[] b = { 91, 83, 83, 91, 80, 89, 99, 79, 88, 87 };
private static byte[] c = { 113, 120, 9 };
private static byte[] d = { 93, 82, 88, 78, 83, 85, 88, 18, 79, 76, 89, 89, 95, 84, 18, 93, 95, 72, 85, 83, 82, 18, 110, 121, 127, 115, 123, 114, 117, 102, 121, 99, 111, 108, 121, 121, 127, 116 };
private static byte[] e = { 111, 116, 125, 17, 13 };
Un tableau avec des nombres obscurs. Si ce n’est pas de l’obfuscation de chaîne de caractère je ne m’appelle plus ** (hehe mince).
En observant le fichier a.java, on remarque qu’une fonction s’amuse avec ces chaînes:
for (Object localObject2 = Integer.toHexString(localObject1[i] & 0xFF); ; localObject2 = str)
{
if (((String)localObject2).length() >= 2)
{
StringBuffer localStringBuffer2 = localStringBuffer1.append((String)localObject2);
i += 1;
break;
}
str = "0" + (String)localObject2;
}
Note : j’ai du réecrire des petites portions du code originel car il ne compilait pas.
Juste pour être sûr, je regarde le fichier ReverseMe.javaet b.java. L’application utilise la reconnaissance vocale et une fois un certain mot acquis, il le compare à une chaine de caractère récupérée par a.java.
ArrayList localArrayList =paramIntent.getStringArrayListExtra("android.speech.extra.RESULTS");
if ((!localArrayList.isEmpty()) && (a.b((String)localArrayList.get(0))))
{
TextView localTextView = this.b;
String str = a.a((String)localArrayList.get(0));
localTextView.setText(str);
}
On voit ici clairement que l’on compare une chaîne de a.java avec la chaîne récupérée par la reconnaissance vocale. Je n’explique pas tout le code n’étant pas du tout un développeur android (mais J2ME pour la petite histoire, au pays du caribou on aime (trop) blackberry).
En réecrivant en partie a.java, j’arrive à dumper les chaînes de caractères encodés:
a:f9dd11ff6857af73ac9a944dfc52f41b b:google_sdk c:MD5 d:android.speech.action.RECOGNIZE_SPEECH e:SHA-1
La chaîne ‘a’ correspond au MD5 de salope (que l’on trouve sur Google). C’est vraiment charmant. Je n’explique pas le SHA-1. Cet indice a sûrement permis aux non francophones de finir ce challenge.
J’installe (enfin) l’application apk sur mon HTC DESIRE HD (torse mis en avant). Fort de mon petit mot salope je le prononce a tue tête à mon téléphone. Cela ne fonctionne pas. Mon téléphone est en anglais. Je passe la reconnaissance de voix en français. Ca ne marche toujours pas. Impossible.
Et là, une petite subtilité qui aurait pu me faire passer à côté du flag. Le filtre sur les mots à connotations sexuelles est activé par défaut. Merci Google. Et voilà, l’application me donne un hash après avoir prononcé ces belles paroles à mon téléphone. Plus précisement il me donne le SHA-1 de “salope”.
Encore 4 petites heures pour faire tout ça.
Conclusion
J’ai passé un superbe week-end grâce à tout cela. C’était ma première participation à un évenement du genre. Je regrette juste de ne pas avoir eu le temps de regarder certains challenges (notamment Crypto300 qui était une application client/serveur en python) mais je n’ai pas eu le temps. Pour pouvoir plus marquer il n’y a pas de secret: s’entrainer plus et lire plus nibbles, mais également motiver son équipe. Je remercie seb qui était toujours présent pour nous relancer dans la course, ça m’a motivé à rester concentré sur le même problème pendant 4 heures d’affilé. N’ayant pas l’habitude de l’exercice, la phase de compréhension des outils est très importante. Je retiens qu’il ne sert à rien de sauter d’étape en étape en esperant gagner des flags facile. Pour moi, la technique est vraiment de se concentrer avec tout ses moyens sur un problème. C’est ce qui a coulé mon équipe, les gens se sont éparpillés sur tous les problèmes en même temps, et n’arrivant à en résoudre aucun, ils se sont découragés. Culture fast food (je donne des leçons de vie maintenant, on aura tout vu). On va essayer de faire mieux la prochaine fois.
Je suis vraiment admiratif de mecs comme rootBSD ou nibbles que j’ai déjà cité pour leur boulot de vulgarisation. Et voilà j’essaye moi aussi de poser ma petite pierre (un petit caillou) à l’édifice.
“On va essayer de faire mieux la prochaine fois.”
La prochaine fois c’est DEFCON mon gros, Va falloir un BSD qui tient tout le weekend au moins
Mon BSD tournera sous GNOME3 donc plus de problème
Plus serieusement on a quelques challenges avant Defcon.