To search

w3pwnz

w3pwnz, therefore we are

Thursday, October 18 2012 16:03

HackYou CTF - Crypto100, Crypto200, Crypto300 Writeups

Crypto100 - Schneier's Algorithm



cry100.jpg

Download file cry100.jpg
This is a code that Bruce Schneier likes to insert as an autograph.
Read from the last column to the first to discover the flag.

Flag: hackyouisthebestestctfftw

Crypto200 - XOROWbIu WbI(|)P



Download file cry200.txt.enc
The title suggests it's XOR, so let's launch a XOR analysis, here with Cryptool:
cryptool_xor.png
We are not done yet, but that's quite a good start!
We can assume the first word is "Congratulations", and deduce the final XOR key from it and the corresponding bytes in the ciphertext:

awe@awe-laptop ~ % hexdump -C cry200.txt.enc|head -n  1
00000000  d5 cb 44 a4 e4 12 e2 d1  46 a2 e2 1a f9 ca 59 e2  |..D.....F.....Y.|
awe@awe-laptop ~ % echo "Congratulations"|hexdump -C|head -n 1
00000000  43 6f 6e 67 72 61 74 75  6c 61 74 69 6f 6e 73 0a  |Congratulations.|
>>> s1 = "d5 cb 44 a4 e4 12 e2 d1  46 a2 e2 1a f9 ca 59 e2".replace(' ','').decode("hex")
>>> s2 = "43 6f 6e 67 72 61 74 75  6c 61 74 69 6f 6e 73 0a".replace(' ','').decode("hex")
>>> ' '.join('%02x' % (ord(s1[i]) ^ ord(s2[i])) for i in range(len(s1)))
'96 a4 2a c3 96 73 96 a4 2a c3 96 73 96 a4 2a e8'

96 a4 2a c3 96 73 is repeated, that's our XOR key.

Now let's decrypt the whole file:

#!/usr/bin/env python2
 
txt = open("cry200.txt.enc", "rb").read()
key = "96 a4 2a c3 96 73".replace(" ", "").decode("hex")
 
def my_xor(cipher, key):
    keylen = len(key)
    res = ""
 
    for pos, c in enumerate(cipher):
        res += chr(ord(c) ^ ord(key[pos % keylen]))
 
    return res
 
print my_xor(txt, key)

Congratulations! While the quick brown fox jumps over the lazy dog, the plain xor cipher is still very unsecure when the key is much shorter than the message. Your flag: Foxie Dogzie Crypto Pwnd

Flag: Foxie Dogzie Crypto Pwnd

Crypto300 - Hardcore



Download file cry300.py.

Here is what the algorithm does:

  • - Init sbox (SALTED_BOX) with range(128).
  • - add_key(SALTED_SBOX, KEY)
  • - every time it receives something from a user, it splits user input into two equal size blocks (k and m), and calls encrypt(SALTED_BOX, k, m)
  • - return hex-encoded result of the encrypt call to the user

If you are too lazy to open the file, here is add_key function:

def add_key(sbox, k):
    for i, c in enumerate(k):
        sbox[i], sbox[ord(c)] = sbox[ord(c)], sbox[i]
        for i in xrange(len(sbox)):
            sbox[i] = (sbox[i] + 1) % 128
    return

Notice this is all reversible as long as we have an idea of the inital sbox, which is the case here, we know it was range(128).
Now we must submit an even sized string, let's study the encrypt() function:

def encrypt(sbox, k, m):
    sbox = sbox[::]
    add_key(sbox, k)
 
    c = ""
    for ch in m:
        c += chr(sbox[ord(ch)])
        sbox = combine(sbox, sbox)
    return c

The sbox is copied (sbox = sbox[::]) so that every time you will encrypt something, sbox will remain in the same state as above, salted with our challenge flag.
What about if we submit a string of 2 characters? 'k' will contain the first one, 'm' the last. So in the for loop, we will bypass the combine() call.
Simply perform 127 queries to extract the result of add_key(sbox, k). It is then trivial to reverse it and obtain sbox (SALTED_BOX).
It is indeed possible to optimize this process and to save queries by detecting a constant increment in dumped sbox characters, but I prefered the easy dirty way ;)
We only need to revert add_key(range(128), KEY), now that we have its output.
A quick bruteforce does it well, for each possible key length.
Once again, the optimization could save this but ... :D

Here is my code:

#!/usr/bin/env python2
 
import socket
import string
 
#HOST = 'localhost'
HOST = '93.191.13.142'
PORT = 7777
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect((HOST, PORT))
 
res = [-1]
 
for i in xrange(1, 128):
    txt = '1' + chr(i)
    s.sendall(txt)
    data = s.recv(1024)
    res += [ord(data.rstrip().decode("hex"))]
 
s.close()
 
for i in xrange(0, 128):
    if i not in res:
        res[0] = i
        break
 
res[0], res[ord('1')] = res[ord('1')], res[0]
 
res = map(lambda x: (x - 1) % 128, res)
 
print res
 
ref = res[:]
 
for bf in xrange(1, 128):
    pwd = ""
    dump = True
    res = ref[:]
 
    for pos in reversed(xrange(0, bf)):
        res = map(lambda x: (x - 1) % 128, res)
 
        for i, c in enumerate(res):
            if c == 2 * pos:
                break
 
        res[pos], res[i] = res[i], res[pos]
 
        if not chr(i) in string.printable:
            dump = False
            break
 
        pwd = chr(i) + pwd
 
    if dump:
        print "-" * 80
        print pwd

And its output:

% ./sploit_cry300.py
[86, 3, 13, 122, 14, 2, 75, 28, 29, 5, 77, 19, 34, 6, 74, 8, 83, 38, 127, 41, 40, 15, 1, 31,
89, 88, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72,
73, 46, 32, 76, 36, 78, 79, 80, 81, 82, 42, 84, 85, 26, 87, 51, 50, 90, 91, 92, 93, 94, 95,
96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
114, 115, 116, 117, 118, 119, 120, 121, 43, 123, 124, 125, 126, 44, 0, 48, 49, 27, 4,
35, 39, 7, 45, 9, 10, 11, 12, 33, 30, 47, 16, 17, 18, 37, 20, 21, 22, 23, 24, 25]
--------------------------------------------------------------------------------
jj	
--------------------------------------------------------------------------------
m	
--------------------------------------------------------------------------------
<is`th1s`k3y`l0n9`en0ugh?>
--------------------------------------------------------------------------------
1sek3yhl >9`en0ugh?> !"#$% !"#$%
--------------------------------------------------------------------------------
snk3y?l"!9`en0ugh?>!"#$%&'!"#$%&'
--------------------------------------------------------------------------------
0k3y>l$#9`en0ugh?>"#$%&'()"#$%&'()
--------------------------------------------------------------------------------
k3y#l&%9`en0ugh?>#$%&'()*+#$%&'()*+
--------------------------------------------------------------------------------
3y%l('9`en0ugh?>$%&'()*+,-$%&'()*+,-
--------------------------------------------------------------------------------
y'l*)9`en0ugh?>%&'()*+,-./%&'()*+,-./

Flag: <is`th1s`k3y`l0n9`en0ugh?>

Sunday, March 25 2012 14:34

NDH2k12 Prequals - We are looking for a real hacker - Unknown text

UnknownText.png
File sp111

After opening the sp111 text file, we guessed that it was encrypted with vigenere.

We tried an auto-decrypt with http://www.apprendre-en-ligne.net/crypto/vigenere/decryptauto.html, revealing that “OFJZUANDEOQDK” would be the most probable key.

We reconstructed the following plain text :

; HI,
 
; I WAS DISCRETELY WANDERING AROUND AS USUAL YESTERDAY. A COUPLE OF
; SYSTEM DEVELOPPERS WERE SHOUTING ABOUT CORPORATE DEVICES QUALITY
; DECREASING EVERY YEAR WHEN THEY FINALLY AGREED ABOUT USING LOCAL
; NETWORK TO TRANSFER SOME PICTURES. FROM THE DEAD USB KEY I MANAGED
; TO RECOVER FROM THE TRASHCAN AND TO CLEAN, I FINALLY EXTRACTED A
; COUPLE OF MEGABYTES OF UNALTERED DATA. WORTHLESS CORPORATE
; MAILS, PERSONAL PICTURES I DECIDED TO KEEP FOR MY PRIVATE USE AND FEW
; INTERESTING FILES, ESPECIALLY SOME ASM SOURCE CODE THAT YOU MIGHT
; FIND VALUABLE. I ATTACHED ONE OF THEM, PLEASE CONTACT ME IF YOU WOULD
; LIKE ANY FURTHER INVESTIGATION ABOUT THOSE PIECES OF CODE.
 
; TEST PROGRAM #1 - BUILD #35 FOR SCIPAD
; HTTP://SCITEEK.NUITDUHACK.COM
 
; SOME INCLUDES #INCLUDE INC/STDLIB.INC
 
; THIS ROUTINE ASKS FOR A PASSWORD AND PUT THE ADDRESS IN R5 AND THE SIZE IN R0
 
.LABEL ASK_PASSWORD
   ; DISPLAY A PROMPT
   MOVL R0, :PWD_MSG
   CALL :PRINT
 
   ; ALLOCATE SOME SPACE ON STACK
   SUBB SP, #8
   MOV R5, SP
   MOVL R0, STDIN
   MOV R1,  R5
   MOVB R2, #10
 
   ; READ THE PASSWORD FROM STDIN
   CALL :READ
 
   ; RESTORE THE STACK POINTER
   ADDB SP, #8
 
   ; RETURN
   RET
 
; OUR MAIN
;
; BASICALLY, THIS PROGRAM DOES NOTHING USEFUL ... IT IS JUST A SAMPLE ;)
 
.LABEL MAIN
   ; DISPLAY A WELCOME MESSAGE
   MOVL R0, :WELCOME
   CALL :PRINT
 
   ; ASK FOR A PASSWORD
   CALL :ASK_PASSWORD
 
   ; DISPLAYS AN ERROR
   MOVL R0, :ERROR
   CALL :PRINT
 
   ; QUIT
   END    
 
; TEMP ROUTINE (NOT USED ANYMORE)
 
.LABEL TEMP_ROUTINE
   MOVL R0, :FLAG_FILE
   CALL :DISP_FILE_CONTENT
   END
 
.LABEL WELCOME
.DB "WELCOME ON SCITEEK' SCIPAD SECURE SHELL !",0X0A,0
 
.LABEL PWD_MSG
.DB "PLEASE ENTER YOUR PASSPHRASE: ",0
 
.LABEL ERROR
.DB "NOPE. IT IS NOT THE GOOD PASSWORD",0X0A,0
 
.LABEL HINT
.DB "SCITEEK.NUITDUHACK.COM:4000",0
 
.LABEL FLAG_FILE
.DB "ESOASOEL.TXT",0

Wednesday, April 6 2011 20:00

NDH2k11 Prequals - Crypto300

La crypto300 est sous la forme d'un ensemble de fichiers python :

crypto300> ls
braid.py   client.py  flag.py   network.py   peer.py   server.py

La première partie de cette épreuve consiste donc à comprendre que font ces fichiers. Heureusement le code est clair et bien écrit.

  • braid.py : Ce fichier est en réalité le coeur de l'épreuve dans lequel toutes les opérations cryptographiques sont faites. Le cryptosystème fonctionne à base de permutations.
  • client.py : Ce fichier contient le code du client (nous) qui va se connecter au serveur.
  • server.py : Ce fichier contient le code du serveur hébergé sur les machines de la ndh, sur lequel on va se connecter.
  • flag.py : Ce fichier contient un fake flag, le saint graal pour nous... celui qui sera envoyé par le serveur, enfin on espère.
  • network.py : Ce fichier contient des classes implémentant l'accès bas niveau au réseau.
  • peer.py : Ce fichier contient des classes implémentant un transfert sécurisé des informations.

Une première exécution du client nous donne le résultat suivant :

crypto300> python client.py
[Crypto300 sample client]
[i] Welcome on Goofyleaks. Can I haz ur public kay ?
[+] Your leaked flag: ##NOT ALLOWED##

Ca commence mal, on a pas le droit d'accéder au flag. Une analyse plus fine du code de network.py et notamment de la fonction run de ServerWorker nous donne un peu plus d'informations sur ce qui se passe réellement :

...
           if str2hex(pubkey) in self.allowed_pubkeys:
                # authenticated ! (public key is allowed)
                enc_data = self.peer.encryptData(GOODBOY_FLAG)
                self.__send(enc_data)
            else:
                # well, public key is not allowed, send error
                enc_data = self.peer.encryptData('##NOT ALLOWED##')
...

Si on a pas la bonne clé publique, on aura pas le bon flag. La bonne clé se trouve dans le fichier server.py :

...
       # bind peer instance to a socket (and set up a single allowed public key)
        self.s = ServerSocket(peer,allowed_pubkeys=['0F0C11040108060B05150E1000090A030D1312140207'])
...

On commence à comprendre un peu plus le problème... On sait quelle est la clé publique, mais il va falloir trouver la clé privée correspondant à cette clé publique.

Une analyse plus détaillée des fichiers nous permet de bien comprendre la communication qui est faite entre le client et le serveur :

CLIENTSERVEUR
Connection
Envoi MOTD
Réception MOTD
Envoi Clé Publique Serveur
Réception Clé Publique Serveur
Envoi Clé Publique Client
Réception clé Publique client
Génération secret partagé avec clé publique serveur Génération secret partagé avec clé publique client
Si bonne cle publique chiffre bon flag flag, sinon chiffre mauvais flag
Envoi flag chiffré
Réception flag chiffré
Déchiffrement flag chiffré



Le secret partagé est en réalité un sha1 obtenu à partir d'opérations sur la clé publique de l'interlocuteur et d'une valeur commune entre le client et le serveur 0D1214040108060F050C0E0207030A151009000B1311 que l'on peut trouver client.py et server.py. Ce sha1 sert comme clé à l'algorithme blowfish pour chiffrer le flag envoyé par le serveur. Bien évidemment, la génération du secret partagé aboutit à la même valeur chez le client et chez le serveur s'ils possèdent les clés privées correspondantes aux clés publiques envoyées. Ici impossible de faire quoique ce soit, la vulnérabilité n'est pas dans le chiffrement du flag, mais dans l'obtention de la clé permettant ce chiffrement.

La génération de la clé privée et de la clé publique chez le client et chez le serveur se font à partir de la même valeur commune citée plus haut. La dérivation se fait dans braid.py dans le constructeur de la classe BraidKey. La clé privée est d'abord initialisée à la valeur 000102030405060708090A0B0C0D0E0F101112131415 (soit 22 octets différents) puis les 11 premiers octets sont mélangés pour le serveur et les 11 derniers pour le client. La clé publique est ensuite obtenue à partir de cette clé privée, à partir de deux méthodes : combine et reverse.

Il y a donc 11! clés privées différentes (11 octets fixes puis 11 octets mélangés) soit 39916800. A la vue des writeup déjà écrits sur cette épreuve, la majorité des teams se sont arrêtés là et ont bruteforcé l'ensemble des 11! clés possibles. Malheureusement mon PC ayant déjà trop chauffé durant la crypto200, nous avons essayé de réduire l'espace de recherche pour simplifier le calcul.

Pour cela il faut bien comprendre les méthodes combine et reverse.

  • combine

La méthode combine mélange un tableau en fonction d'un autre.

Tableau 1

000102030405060708090A0B0C0D0E0F101112131415
1514131211100F0E0D0C0B000102030405060708090A



Tableau 2

000102030405060708090A0B0C0D0E0F101112131415
000102030405060708090A1514131211100F0E0D0C0B



La méthode Tab1.combine(Tab2) donne :

000102030405060708090A0B0C0D0E0F101112131415
0B0C0D0E0F101112131415000102030405060708090A



On prend l'élément 0 de tab1 (ici 0x15) et on prend le 0x15 ème élément de tab2 (donc B), qui deviendra l'élément 0 de Tab1.combine(Tab2).

  • reverse

La méthode reverse retourne un tableau par rapport à ses indices :

Tab1.reverse() donne :

000102030405060708090A0B0C0D0E0F10111213141516
0A09080706050403020100161514131211100F0E0D0C0B



On prend l'élément 0 de tab1 (ici 0x15) et 0x15 ème élément devient donc l'élément 0 de Tab1.reverse().

Maintenant que ces deux méthodes sont bien assimilées regardons comment les éléments s'enchainent pour obtenir la publique en fonction de la clé privé et surtout regardons s'il est possible de reverser le processus.

L'analyse (simplifiée) de braid.py donne ça :

Priv = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21];
Priv.shuffle(offset/2);  # La deuxième partie de Priv est mélangée
PrivR = Priv.reverse();
T = K.combine(PrivR);
Pub = Priv.combine(T);

K est la valeur connue citée plus haut, et T ne se trouve pas dans le programme mais je l'ajoute pour simplifier le calcul. On connait Pub (la clé que l'on doit envoyer au serveur pour qu'il nous envoie le bon flag), on connait K, et on connait la moitié de Priv.

Posons ce que l'on connait :

indice000102030405060708090A0B0C0D0E0F101112131415
PRIV000102030405060708090A???????????
PRIVR??????????????????????
K0D1214040108060F050C0E0207030A151009000B1311
T??????????????????????
PUB0F0C11040108060B05150E1000090A030D1312140207



Dire que l'on ne connait pas pas PrivR est faux. On en connait au moins une partie. Etant donné que PrivR = Priv.reverse(), on connait la première moitié de PrivR, elle est égale à la première moitié de Priv (seulement car les 11 premiers octets de Priv sont 0,1,2,3,4,5,6,7,8,9,10,11). De la même façon, on connait une partie de T car Pub = Priv.combine(T). Donc la première moitié de T est égale à Pub encore une fois seulement car les 11 premiers octets de Priv sont 0,1,2,3,4,5,6,7,8,9,10,11).

On met à jour notre tableau :

indice000102030405060708090A0B0C0D0E0F101112131415
PRIV000102030405060708090A???????????
PRIVR000102030405060708090A???????????
K0D1214040108060F050C0E0207030A151009000B1311
T0F0C11040108060B05150E???????????
PUB0F0C11040108060B05150E1000090A030D1312140207



On sait que T = K.combine(PrivR), donc on peut essayer de voir si certains octets de PrivR peuvent être découverts.

indice000102030405060708090A0B0C0D0E0F101112131415
PRIV000102030405060708090A???????????
PRIVR000102030405060708090A?150F0E0B??0C?11?
K0D1214040108060F050C0E0207030A151009000B1311
T0F0C11040108060B05150E???????????
PUB0F0C11040108060B05150E1000090A030D1312140207



Vu que PrivR = Priv.reverse() on finit par découvrir certains octets de Priv.

indice000102030405060708090A0B0C0D0E0F101112131415
PRIV000102030405060708090A0F12?0E0D?14???0C
PRIVR000102030405060708090A?150F0E0B??0C?11?
K0D1214040108060F050C0E0207030A151009000B1311
T0F0C11040108060B05150E???????????
PUB0F0C11040108060B05150E1000090A030D1312140207



Il ne reste donc plus que 5 octets inconnus dans la clé privée, on a donc diminué l'espace de recherche de 11! à 5! soit 120. Il suffit de tester ces 120 possibilités et de voir celles qui respectent le padding PKCS5 fait lors de l'envoi du flag. Une seule réponse correspond pour la clé 000102030405060708090a0f12110e0d151410130b0c qui nous permet de déchiffrer le flag : Br4iDCrypto_i5_b3au7ifu11

Tuesday, April 5 2011 19:23

NDH2k11 Prequals - Crypto200

On a un code source qui génère des password au hasard et un fichier jpg encrypté.

Un block de 8 bytes qui commence à un rang multiple de 8 bytes se répète très très souvent. Plusieurs fois de suite, au début, au milieu, à la fin...
On comprend donc que c'est un chiffrement symmétrique par blocks de 64-bits du genre de DES. On se doute aussi que le block de 8 qui se répète correspond à un byte répété plusieurs fois de suite, très probablement des null bytes vu la structure des jpg en général.

Vu le nom du fichier (bf-encrypted.jpg) on devine que c'est du BlowFish (c'est bien du DES-like).

Du coup on a pas vraiment le choix, il faut bruteforcer.

Vu le fichier de génération de password fourni on devine que la longueur de la clef est de 8 bytes. ymvunjq y trouve une faille qui permet de ne bruteforcer que sur les 5 premiers bytes (les 3 suivants sont déduits par la suite).

Ainsi on lance un bruteforce qui passe par les 62^5 passes possibles (62 étant le nombre de caractères dans le charset).

BAAL trouve le passe eynnoXAd. On l'utilise pour dé-blowfisher l'image avec le code suivant:

#include "blowfish.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
void bruteforce_key (void)
{
    unsigned long L = 1, R = 2;
    BLOWFISH_CTX ctx0;
    char PASS[10] = {0};
 
    // Test to check if the blowfish code runs properly on given computer
 
    Blowfish_Init (&ctx0, (unsigned char*)"TESTKEY", 7);
    Blowfish_Encrypt(&ctx0, &L, &R);
    printf("%08lX %08lX\n", L, R);
 
    if (L == 0xDF333FD2L && R == 0x30A71BB4L)
        printf("Test encryption OK.\n");
    else
        printf("Test encryption failed.\n");
 
    Blowfish_Decrypt(&ctx0, &L, &R);
 
    if (L == 1 && R == 2)
        printf("Test decryption OK.\n");
    else
        printf("Test decryption failed.\n");
 
    // Bruteforce, loop through first 5 chars
 
    char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-!$%*+[]()";
    int a0, a1, a2, a3, a4;
 
    for(a0=0;a0<62;a0++){
        for(a1=0;a1<62;a1++){
            printf("%i %i - ", a0, a1); // Display progress
            for(a2=0;a2<62;a2++){
                for(a3=0;a3<62;a3++){
                    for(a4=0;a4<62;a4++){
                        PASS[0] = charset[a0];
                        PASS[1] = charset[a1];
                        PASS[2] = charset[a2];
                        PASS[3] = charset[a3];
                        PASS[4] = charset[a4];
                        PASS[5] = charset[PASS[4] % 62];
                        PASS[6] = charset[PASS[5] % 62];
                        PASS[7] = charset[PASS[6] % 62];
                        L = 0;
                        R = 0;
 
                        Blowfish_Init (&ctx0, (unsigned char*)PASS, 8);
                        Blowfish_Encrypt(&ctx0, &L, &R);
 
                        if (L == 0x8EDE92F0 && R == 0xD0D99926){  //Expected crypted text
                            printf("*** Success *** Password: %s\n", PASS);
 
                            a0 = 100; a1 = 100; a2 = 100; a3 = 100; a4 = 100;
                            system("PAUSE");
                        }
                    }
                }
            }
        }
    }
 
    puts ("[+] DONE");
}
 
void decrypt (void)
{
    BLOWFISH_CTX ctx0;
    unsigned long L = 0x67A2204C , R = 0x967FB36E;
    int i;
    FILE *input = fopen ("bf-encrypted.jpg", "rb");
    FILE *output = fopen ("bf-decrypted.jpg", "wb+");
 
    if (!input)
    {
        puts ("[-] File not found");
        return;
    }
 
    while (!feof (input))
    {
        L = 0;
        R = 0;
 
        for (i = 0; i < 4; i++)
            L = (L << 8) + fgetc (input);
 
        for (i = 0; i < 4; i++)
            R = (R << 8) + fgetc (input);
 
        Blowfish_Init (&ctx0, (unsigned char*)"eynnoXAd", 8); // This is the password obtained from step 1
        Blowfish_Decrypt(&ctx0, &L, &R);
 
        for (i = 0; i < 4; i++)
            fputc ((L >> (8 * (3 - i))) & 0xff, output);
 
        for (i = 0; i < 4; i++)
            fputc ((R >> (8 * (3 - i))) & 0xff, output);
    }
 
    fclose (input);
    fclose (output);
 
    puts ("[+] DONE");
}
 
int main(int argc, char **argv)
{
    if (argc < 2)
    {
        printf ("Usage: %s step\n"
                "\tStep 1 : Bruteforce the key\n"
                "\tStep 2 : Decrypt the ciphertext\n", argv[0]);
        return 1;
    }
 
    if (argv[1][0] == '1')
        bruteforce_key ();
    else if (argv[1][0] == '2')
        decrypt ();
    else
        puts ("[-] FAIL\n");
 
    return 0;
}

Le code source du blowfish est pris d'ici: C'est celui de Paul Kocher.

L'image une fois décryptée donne le flag: Cod3monk3ys_4re_3viL

bf-decrypted.jpg

NDH2k11 Prequals - Crypto100

La première crypto était sans nul doute le challenge le plus simple de ces pré-qualifications, elle se présentait sous la forme d'un fichier texte du nom de lorem.txt

Lorem faisant clairement référence au Lorem Ipsum, texte de remplissage de faux site très connu.

Voici le cipher :

NFPTF WAWMG SSCQY AMG CDCI, WIT TWFAIEVLAUHG GYGMICMWHI GFPZMUHCK KPLGL ZWHTRRVPA RRE, LPCT GPH JBDRTWZ ZMFWJ GPVIWMK. OAXIKJQIF PVA CXEFI KUEMVP PXWHO, ESCV JTZSGJW MQSCTGCKC SNW DYKWXTZV AZMFVZOJX, BPUMY BYJ GB MXVCD, KPZBL JSWXPZUPA PNELQ SBOX. WMMEIEFPAWR UTCAXFTWIOT PVEACW NTTS JM. ALWKU RSEXHTPVU VQI LOAMWH TVRV BB, XVPTGSNBE PGLTQ RNPYYNO, ZB PM DSEKYAPLU HZGH CK CABH, XEYHP HFPLK ERPVYC OSYIFUIMJ GA CVAC, DMCMSD IM MTH. CGJBYF ORSGBG DGWFTVZUXCI FKK NTWS DIV YI, WLUWMRQKJQT NH QIJGTRKWT AGRNVPXLEFI, WN SMTVBUWG XFJJMDLX VCVRZUZQQ NPKC CNBN QGFAMJ, GYIX FGD GS KWDYK GPYIKZ. XVBKE NGHWY, SVCD RVE WPEEGKPP GCY, TJYIMLO WWVGC DCING ASJNP EIEB QH QQCMG, VCCTGLXW CGV, NVVPXGAEO L. ZWBXGLNH DSYWKNPM HPPDOH QFNSQW NGECPG O AIJ, NDVKQY KSAFZKTGHFQ FIC, MDRLZHVGK YCMS PWL UAMHWLB TEQZBTGH, TRLYGHLO ACVCKJ HJLHZ MHMJQ DCNVE RW CGQXFZ. WAN KMKCL, I HVCD DTNUTEL ZTPZU UQFU HRAXEWDMK PJPGWAIXR, ULQRBDTX NYCIECAQW HNCYBVCCTWL KMKCL, MKRV ECFNS GIKNXFLNBU PNELQ TKOE QGHIIJ. ULL HNRZZJL EFMK MTH FFPW.

MAVVETK QZRMVXE UQUMG RPZK JM ALYJCH, SIEP UEHTZQ CBPS PSWJW UKHU IH, CK YBXH XM, DYRXLU HUIG GEGB OWEEW JTHV UBAGVRZR. QEOYHAN BECGZCEQC, GCAESYXWMFYV KU WVACIC BNG NVSM VVRXPLE, FKK CVXH QIDCH AZUP. CPGTZAXXG TR KYS ELIBM HVIEGHLWX, QSFTWLCKI WNIZRIBG DML, YVIJVHA WBFRJTL QZRYOT GFOTWHB KERTZSC. UMCH ZZVHM HVEKSB HRTS WN TX, RF HLMCKJAXGU ASKOTVV, UVLEYGJ ZATBOMLCXW NKZQ ITGK LJEZL SJWX. JLUJM QBTSG FNWD QGFAMJ C UCRP, CVLTTB TR DCVYCC XCMF, OFJABG EIDFJW AWZBS RIVR GNHCYE, OI HZIUQWFKD RXGQTHMHI HLKZ DIAGEYIBG. DEHCTR JCWQIA NZRDKO DYKJTRUKZAI CTVRXNA, DIV JTRRVPJYF, OFJTLHTI MFIVZELA ZHNGSITHP RGH JX VTVA XROGSH. NZEVAWXIJ OP MX NOVR. BB JZPMNEEK CKQTVUTGCZ SCEL WDRUKTMRGWD LDG JPP. NCIEV KHKYYKJ, LDG EFMK CC HZIUQWFKD OJTA TR. NYHXZDBTYZ UVB UTINMTOH JRWJQFHU MGKTAFW, KOHGZRPB TEGKGJF, BFPDU HEGKLV MQ SLGHJIP, JWLBIEVBU QV VVKEHF XEKMP QVVBA. YG FRNXUID SJHPVV PBVG IKKYT BDDYE YAMK, DPJIAFLK XW FTWMM BELTPA MA. FZYB ICCXLCISI GYWW FEVJTKWDUMY KIC XPDEZWJ, GS BB NSFMTGKGACIE CVLTTB OMUNJQ RPAM.

IG ORSGBG TR MN XR, MGS ZMFWJ KTMID, IYYI ICGPNIAF HSPF DPPDYCXVUXCI, RTRR KBHLI SGTX EWSTE NOVR LBGT. PWWIYJ TPAYF UVB IKWDXAKJI ECAWUHG, LR EKOPWWHIMLO KQKAKJQXF QZQEISS KCJQXV, GXCHMOD PSWJW JWZXIAFZQHX WYXWATV MQSCXCCK FTGRCIJCI WFNSQGVVLBXG. OFKMY TVFU SMS YGF NATQPVSN LMJK, UCPYC ESAEOX RMFAE WGYUIAVLK KNZAYLUII, EQU VYYNRK. EHGFIJY SEGKICW ZCJQP GIWPSG, XR GJHAIYNLQ TN IE YL MDPCKJQXHFZL, HTUTXLCH ET ULU IHKJKDW ALIUYCEJ GUQQ WWJRD, TQ TH NIAYKRHB MA UVB HXBPGLOH. WRGWM QNWIGH FOFVAM, IICNBA WRF DYVGO WEUOH, RLPJ QR GCTGIB, GLKANIMJ JLVHEGIGI OWEEW HXFY RVZXGKKMG TQ WEUCCMR. WSBVVEVQ RHBOMEYCXLO, SMGGWJ LJGQ DEYCIXZU YPSAELQ. TM BPUMY UETKSQWVU R LXLZ NSFMTULCA BMAEZBJGH, EIDFJW MGZBMOWCSB MSWPMM TPVKMMRQ, PLJAT GTX NYA ICGTMRGWD ZXUSYHMG, AETWZ MYVUDMS XZPQWHIYD C, UWRHODW JEHCMUYH EDGA XLNTVRGT. JPRWHPXZU SWVRO, LR PGHP, RGH YYJVV QR IGC NDKHL EMAJI, UQUMG FWJAXIWE PGVDVKKZ MY ZCLPXL, HCMKNXULG HTMDWVR BTUYE UOGESKACV FKK.

JDKSX TWFAIEVLAUHG VJXM QFVSVXXLT, PVXRIVP PNUFI AH UETKSQWVU VPPM COMG GPYIKZ, AYFRVLSBGDI WATX ZPAMKRT JCFNW AIFUIMSWZ IH. ZK TPPL TCMFAXPCC SIGVPZY, RHAXSVI AMXWSI ZRNZR TEWE EEYI. RZUS VIP, CK TTE OWMIOPQ CKNCPN, UVB KXZ DIE GPYIKZ DIY WCJPFQZVHYG HFNVZ, HVCD LJEZL, IL MTQ MGZBMOWCSB LWE. ZWFXX EGJ, TIPVLQ JM, RZRWW XR DCLKIACJ PXLID XWGESI, EVUQBFF LTV SEMSG EYCXPVEE, DCYCWWE YL XXW. AWZBS EKJSH VCYWWKJEK PPJL FGU BJBG, XEYHXW CGJBYF FZAINA AVSYHIEV YQWHU JSHISYHAMHI WCJQPVUZ, YRVIXWSH ELRULTPHU LR P WOAMTOH HLKZ, VEZ CDCI THBYW, UR RFP HB EP FLGH EONYK HTG. GJHAIYNLQ GBGFW VYAITVBA RVDY, TXOOXYK HTG, RNPYYNO HSPF GPH HBPVVVYI. MA HVSVBOE MFNTVUWT IX RV, VR XG JPP VCVRZUZQQ, NOVR KTFTYK HXFY YPAM YWTRJL JFPHOIEKG. TIWFC GMGMO GEJCJW FFPW ZRN. UGVGWDWAG TKVUAIW NWTRDK JPVG, XDRVE WTEPGIYI IFZMF, LXHZEBTYF JVLSKSCML PJPGWAIXR YZQX TAPX, EUIXZU LOIFVRQ, IHFESJ NJVGKZ CX EWKPJF BPG.

Si l'on commence par une analyse de fréquence et un calcul de l'indice de coïncidence et sachant qu'un Lorem Ipsum possède un IC de plus de 0.07. On tombe sur 0.040046315846048 signifiant que l'on a affaire à une méthode poly-alphabétique, la plus connue étant le carré de vigenère. La façon la plus rapide d'avoir la réponse est d'utiliser le logiciel Cryptool 1.4.21.

En deux clics ont obtient la clef suivante : CRYPTOLESUPERCHIEN

Et le texte décrypté suivant :

LOREM IPSUM DOLOR SIT AMET, DUI PELLENTESQUE PARTURIENT CONSEQUAT MASSA VENENATIS NEC, URNA SED RHONCUS RISUS IACULIS. ULTRICIES NEC NEQUE SAPIEN IPSUM, NUNC VIVAMUS VOLUPTATE DUI SUSCIPIT TRISTIQUE, NEQUE MUS EU ETIAM, MAGNA FACILISIS LACUS DIAM. SUSPENDISSE SCELERISQUE LECTUS ARCU UT. MASSA CONVALLIS EST SAPIEN ERAT UT, TINCIDUNT LOREM ALIQUAM, ID AT PHASELLUS ARCU AT ELIT, MAGNA DONEC AENEAN VENENATIS ET URNA, MONTES EU SED. LECTUS MAURIS SCELERISQUE SIT PEDE SED ET, SUSPENDISSE UT FERMENTUM SCELERISQUE, ET DICTUMST VOLUTPAT DIGNISSIM ANTE NUNC MOLLIS, ERAT SEM ID RISUS MAURIS. PROIN PROIN, ODIO NEC PHARETRA NON, PRETIUM PORTA METUS PORTA ARCU ID DOLOR, CORPORIS LEO, FRINGILLA A. VEHICULA VOLUTPAT TELLUS MOLLIS AENEAN A PER, TORTOR CONDIMENTUM NON, IMPERDIET ANTE EST ALIQUET PROIDENT, INTERDUM TURPIS JUSTO IPSUM MAGNA EU LIBERO. SIT VITAE, A DIAM FEUGIAT FELIS NIBH FACILISIS VULPUTATE, SUSCIPIT VENENATIS ULLAMCORPER VITAE, EGET NEQUE VESTIBULUM LACUS ERAT MONTES. SED DAPIBUS QUIS SED ODIO.

INTEGER CONUBIA DONEC ENIM UT MAURIS, ORCI MAURIS NIBH LACUS DIAM EU, AT AMET MI, LECTUS AMET ENIM VITAE PEDE SUSCIPIT. BLANDIT MALESUADA, PELLENTESQUE IN ORNARE MUS CRAS GRAVIDA, SIT EGET FELIS WISI. ULTRICIES IN SED AUGUE DIGNISSIM, MALESUADA SAGITTIS SIT, EGESTAS SODALES CONGUE COMMODO INTEGER. QUIS VITAE DICTUM ODIO ET ET, AD ADIPISCING POSUERE, SODALES BLANDITIIS WISI EGET NULLA ORCI. FUSCE MORBI QUIS MOLLIS A NUNC, AENEAN IN LIGULA QUIS, MOLLIS TELLUS JUSTO EGET RUTRUM, UT DIGNISSIM TINCIDUNT DUIS VENENATIS. SAPIEN SAPIEN LITORA SUSPENDISSE PRETIUM, SED PENATIBUS, MOLESTIE ULTRICES VULPUTATE NON UT EROS TEMPUS. ULTRICIES MI ET AMET. MI VOLUTPAT ADIPISCING ERAT CONDIMENTUM NON VEL. VITAE IACULIS, NON QUIS IN DIGNISSIM QUAM IN. VESTIBULUM SED FAUCIBUS FAUCIBUS VIVAMUS, SUSCIPIT PRETIUM, NULLA SAPIEN ID QUISQUE, FERMENTUM MI TEMPOR MASSA METUS. UT DAPIBUS ORNARE NUNC VITAE IPSUM ELIT, BIBENDUM ID RISUS MAURIS IN. DIAM PORTTITOR EROS SCELERISQUE VEL VIVAMUS, ID IN CONSECTETUER AENEAN DICTUM ANTE.

ET MAURIS IN UT IN, VEL RISUS METUS, EGET ELEIFEND QUAM PELLENTESQUE, ERAT VITAE AMET NULLA AMET WISI. LECTUS RISUS SED TRISTIQUE NATOQUE, UT PRAESENTIUM DIGNISSIM COMMODO TACITI, EGESTAS LACUS SUSPENDISSE INTEGER VOLUTPAT HENDRERIT SOLLICITUDIN. AUGUE EROS LEO LEO PLACERAT WISI, NULLA NULLAM NULLA FERMENTUM VULPUTATE, NON NULLAM. POSUERE DAPIBUS MASSA NULLAM, IN PHASELLUS EU UT UT SOLLICITUDIN, SAGITTIS AC SEM EUISMOD MAECENAS ENIM JUSTO, AC ID VOLUTPAT IN SED SENECTUS. SAEPE MAURIS MAURIS, TELLUS SED MAGNA LACUS, NUNC IN TACITI, SAGITTIS HENDRERIT VITAE NIBH PORTTITOR AC LACINIA. ULTRICES CONDIMENTUM, LECTUS NUNC SAGITTIS RHONCUS. ET NEQUE FACILISIS A NISL CONSEQUAT TINCIDUNT, TELLUS VESTIBULUM TELLUS ELEIFEND, NULLA SIT VEL ELEMENTUM BIBENDUM, LACUS EUISMOD ELEMENTUM A, NONUMMY ULTRICES AMET PHARETRA. VENENATIS LOREM, UT ANTE, NON JUSTO IN VEL PORTA AUGUE, DONEC SUSCIPIT LOBORTIS EU MAURIS, TRISTIQUE ALIQUET MAGNA CURABITUR SIT.

LOREM PELLENTESQUE ELIT CURABITUR, INTEGER AUGUE IN FACILISIS ERAT ODIO MAURIS, SUSPENDISSE EGET INTEGER SEQUI PENATIBUS AD. MI CRAS FRINGILLA LACINIA, COMMODO LIGULA VELIT ELIT AMET. NISL NEC, AT VEL ALIQUAM LIGULA, SED VEL SEM MAURIS VEL ULLAMCORPER DOLOR, DIAM NULLA, ET SEM VESTIBULUM SIT. VELIT NEC, LECTUS UT, DONEC IN MAECENAS RISUS TEMPOR, COMMODO NEC ETIAM PULVINAR, BLANDIT UT DIS. JUSTO RISUS CONSEQUAT NIBH SED DUIS, MAGNIS LECTUS DICTUM PRAESENT RISUS SUSPENDISSE FACILISI, ACCUMSAN PHASELLUS UT A DAPIBUS DUIS, NAM AMET ATQUE, AC NON AT AC DUIS LACUS NEC. PHASELLUS RISUS DELECTUS NIBH, VIVAMUS NEC, ALIQUAM QUAM SED PHARETRA. IN FEUGIAT INTERDUM AT ET, ET IN VEL DIGNISSIM, AMET VARIUS NIBH WISI LUCTUS VULPUTATE. MASSA PORTA VARIUS ODIO VEL. DIGNISSIM EGESTAS AUCTOR VERO, DONEC PLACERAT PROIN, RIDICULUS HENDRERIT VULPUTATE WISI AMET, MATTIS EGESTAS, TORTOR TURPIS UT RUTRUM NEC.

Comment faire sans outils ?

En utilisant la méthode de recherche de mot probable du commandant bazeries : http://www.apprendre-en-ligne.net/crypto/vigenere/motprobvig.html

En ce basant sur la probabilité assez grande que le texte commence par "loremipsum" on trouvait CRYPTOLESU.

Qui indiquait que l'on avait affaire à une clef plus grande que 10.

La suite la plus classique étant Lorem ipsum dolor sit amet consectetur adipiscing elit. Et avec cette méthode on trouvait alors : CRYPTOLESUPERCHIENCRYPUUGBSDHELBUARZRYGEEVWILZP

On tombait aussi facilement sur la clef !