Test de dureté des mots de passe sur des bases de données SYBASE (SYB-PROP hash)

Test de dureté des mots de passe sur des bases de données SYBASE (SYB-PROP hash)

Bonjour à tous,

Cela fait pas mal de temps que nous n’avons pas mis à jour notre blog sécurité R&D par manque de temps et sur le fait que de nombreux travaux réalisés ne peuvent être publiés …..

Nous revenons aujourd’hui sur un sujet assez spécifique concernant le reverse et la création d’un module John The Ripper sur un algorithme de hashage assez peu connu utilisé sur des bases de données SYBASE. Nous savons qu’à partir de la version 15.0.1 les hash sont générés via SHA-256 mais pour les versions antérieures (<= 12.5), encore très utilisées en entreprise, l’algo utilisé n’a jamais été reversé jusqu’au bout (FEAL-8).

C’est donc le sujet de ce papier qui va permettre via un cas client de développer un module John The Ripper pour les hash de type SYB-PROP

Un des besoins récurrent des grandes architectures informatique et plus spécifiquement des milieux bancaires, concerne les contraintes relatives à l’évolution des mesures de sécurités suite à un audit de configuration, d’un test d’intrusion ou bien l’évolution d’une politique de sécurité.

Ces contraintes sont bien souvent sous-estimées par les recommandations des missions d’audit, et peuvent amener à une remise en cause d’un système entier alors que des solutions spécifiques peuvent exister.

Nous souhaitons dans cet article vous expliquer une des contraintes et la solution que nous avons proposé de mettre en place.

 

Après maints audits internes, cette entreprise voyait souvent remonter le point « politique de sécurité des mots de passe ». Car effectivement, après un audit, on durcit les mots de passe, pour éviter de se faire « taper dessus » la prochaine fois. Sauf que dans la « vie de tous les jours » d’un Administrateur Système/Développeur/DBA, certaines contraintes font qu’utiliser un mot de passe complexe n’est pas si facile que ça, on finit donc assez rapidement par utiliser la solution de facilité.

Notre cas reprend une société qui pour certaines applications nécessite l’utilisation d’une base de données ancienne par souci de compatibilité. Dans notre cas client, de nombreuses bases de données SYBASE en version 12.5 étaient utilisées.

L’entreprise souhaitait donc disposer d’un outil permettant de tester la dureté des mots de passe de façon rapide et simple. Nous allons dans cet article principalement nous focaliser sur l’outil de check de mot de passe

(Pour les besoins d’anonymisation, nous utiliserons les captures d’écran fournie dans la présentation de Marcell Major à la Hacktivity 2010. Document qui nous a fortement aidé lors de notre recherche. Merci à lui ! https://hacktivity.com/hu/letoltesek/archivum/57/)

 1/ Analyse de l’algorithme de hash utilisé

Après une connexion rapide avec un compte d’administration à la base de donnée, nous nous apercevons rapidement que les hash utilisé sont de type SYB-PROP. Algorithme plutôt inconnu à première vue.

image1

On peut voir dans la capture ci-dessus que 2 algorithmes peuvent être utilisés sur une base de données SYBASE :

  1. Un algorithme de hashage classique SHA-256 utilisé par défaut sur les bases de données SYBASE à partir de la version 15.0.1. Un module John The Ripper existe pour cet algorithme
  2. Un algorithme de hashage non connu nommé SYB-PROP

Une recherche sur Google nous permet de récupérer un document écrit par Marcel Majorr contenant les informations techniques sur cet algorithme https://hacktivity.com/hu/letoltesek/archivum/57/ (à partir de la slide 30 pour les plus pressés 😉 )

Son reverse de l’application SYBASE permet de se rendre compte que la base de donnée SYBASE utilise le workflow suivant pour chiffrer un mot de passe en SYB-PROP :

image6

Nous allons donc analyser ces 2 fonctions avant de développer le code pour John The Ripper

2/ Analyse de la fonction meta_encrypt()

L’application utilise une fonction de chiffrement nommée meta_encrypt

image2

Cette dernière fait appel à un algorithme de chiffrement nommé FEAL utilisant une clé constante comme l’on peut le voir dans la capture ci-dessous

image3

Une recherche google montre que l’algorithme FEAL peut-être exécuté de multiple fois pour obtenir un ‘blob’ chiffré. FEAL-4 réalise 4 tours, FEAL-8 réalise 8 tours , on peut aller jusqu’à FEAL-N etc ….

L’analyse de cette fonction aboutit à la conclusion que la clé constante utilisée a pour valeur : « Q:Whydidtheflydanceonthejar?A:Becausethelidsaidtwisttoopen.HaHa! »

image5

Soit une taille de 64 caractères ou 8 bytes. On peut donc conclure que FEAL-8 est utilisé par notre fonction meta_encrypt()

La fonction meta_encrypt peut donc être représentée de la façon suivante :

 image4

L’analyse entièrement réalisée par Marcel Majorr (on le remercie encore) nous permet donc de recoder la fonction meta_encrypt de la façon suivante :

meta_encrypt()

void meta_encrypt_repro(unsigned char * meta_keysched, unsigned char * result)
{
  unsigned char act_XOR_copy_result[8];
  unsigned int i;

  feal_keysch_repro(meta_keysched);
  feal_encrypt_repro(joke, result);
  for(i=1; i<8; i++)
    {
      feal_keysch_repro(meta_keysched + 8 * i);

      syb_XOR(joke + 8 * i, result + 8 * (i – 1), act_XOR_copy_result);

      feal_encrypt_repro(act_XOR_copy_result, (result + 8 * i));
    }
}
static int state;

Les méthodes feal_keysch_repro et feal_encrypt_repro sont disponibles dans les implémentations en C de FEAL8 disponibles partout sur internet. Nous les avons également mis en annexe de cet article dans le code source complet de notre module.

La valeur meta_keysched quant à elle est retourné par la fonction meta_keysch que nous allons analyser maintenant

3/ Analyse de la fonction meta_keysch

Grâce à l’analyse de Marcel Majorr, nous voyons que la fonction meta_keysch est utilisée pour étirer le mot de passe en clair de l’utilisateur a une valeur de 64 bytes en utilisant un seed.

Son fonctionnement peut-être visualisé ci-dessous :

image7

On obtient donc le code suivant :

ccat_pad_repro pour étendre le mot de passe en clair à 57 bytes à l’aide du char 0x1D

void ccat_pad_repro(unsigned char* password, unsigned char* expanded_password)
{
  int i,pwdlen;
  pwdlen = strlen((const char *) password);
  for(i=0;i<pwdlen;i++)
    {
      expanded_password[i] = password[i];
    }
  for(;i<EXPANDED_PWDLEN;i++)expanded_password[i] = 0x1D;
}

Génération du sel (attention cette génération diffère selon si la fonction srand() est utilisée sur un UNIX ou un WINDOWS)

static int g_seed = 0x3f;

int rnd_rand (void)
{
  g_seed = g_seed * 0x343FD + 0x269EC3;
  return (g_seed >> 0x10) & 0x7FFF;
}

unsigned char salt_prob()
{
  unsigned int random = rnd_rand();
 

   random = random >> 8;
   random = random % 0xFF;
 
  return (unsigned char) random;
}

Fonction d’application du sel sur chacun des blocs étendus

void syb_apply_salt_byte(unsigned char salt, unsigned char * password, unsigned char * result)
{
  result[0] = salt ^ password[0];
  result[1] = result[0] ^ password[1];
  result[2] = result[1] ^ password[2];
  result[3] = result[1] ^ password[3];
  result[4] = result[1] ^ password[4];
  result[5] = result[1] ^ password[5];
  result[6] = result[1] ^ password[6];
  result[7] = result[1] ^ password[7];
}

XOR spécifique SYBASE

void syb_XOR(unsigned char* enc_result, unsigned char* password_block, unsigned char* result)
{
  int i;
  for(i=0; i<8; i++)result[i] = enc_result[i] ^ password_block[i];
}

Fonction meta_keysch finale (attention ici aussi, on fait appel au code FEAL-8 dispo sur internet, cf. code source complet à la fin de l’article)

void meta_keysch_repro(unsigned int seed, unsigned char * password, unsigned char * result)
{
  unsigned char expanded_password[EXPANDED_PWDLEN];
  unsigned char salt_byte;
  unsigned char act_FEAL_key[8];
  unsigned char act_XOR_result[8];
  unsigned int start_pos, block_counter;

  ccat_pad_repro(password,expanded_password);

  salt_byte = salt_prob();

  syb_apply_salt_byte(salt_byte, expanded_password, act_FEAL_key);
  feal_keysch_repro(act_FEAL_key);
  start_pos = seed % 0x30;
  feal_encrypt_repro( (joke + start_pos), result);

  syb_XOR(result, (expanded_password + 1), act_XOR_result);

  salt_byte = salt_prob();

  syb_apply_salt_byte(salt_byte, act_XOR_result, act_FEAL_key);
  feal_keysch_repro(act_FEAL_key);
  start_pos = seed % 0x30;
  feal_encrypt_repro( (joke + start_pos + 1), (result + 8));
  for(block_counter = 2; block_counter<8; block_counter++)
    {
      syb_XOR(result + 8 * (block_counter – 1), (expanded_password + (block_counter * 8) – 7), act_XOR_result);

      salt_byte = salt_prob();

      syb_apply_salt_byte(salt_byte, act_XOR_result, result + block_counter * 8);
    }
}

4/ Le petit fail de SYBASE

Après codage, on s’est aperçu que nous rencontrions le même problème que Marcel Majorr dans la génération des hash. Ces derniers n’étant pas du tout dentique à ceux générés sur la base de données SYBASE.

Heureusement après quelques analyses faites par Marcel Major (encore lui 😉 ), il s’est aperçu que SYBASE s’était trompé dans l’implémentation de FEAL8 en omettant une étape. Les implémentations que l’on trouve sur internet doivent donc être modifiées.

Le détail de cette analyse est disponible dans le doc PDF de Marcel Majr donc des extraits peuvent être vus ci-dessous :

image8

Il faut donc modifier le code source C de l’implémentation FEAL8 en conséquence dans la fonction SetKey() (utilisé dans la fonction meta_encrypt()

image9

Après cette étude réalisée par Marcel Majorr et redécortiquée par nos soins, nous pouvons développer un code permettant de recalculer les hash SYB-PROP depuis le mot de passe en clair de l’utilisateur.
Nous avons réaliser un petit module pour John The Ripper mais ce n’est pas encore complètement propre. Voici en tout cas les résultats obtenus

Avec un fichier contenant un dictionnaire de mot de passe :

image10 Le Top 10 000 (En plus il y a evangeli alors c’est trop la classe)

Et un fichier contenant les hash SYBASE SYB-PROP :

image11

Il nous reste plus qu’a lancer le john modifié avec les deux fichiers en paramètre :

image12

C’est beau de lancer un programme en root J

Nous avons donc dans notre résultat le user « test12 » avec un mot de passe étant contenu dans le TOP 10 000, la boucle est bouclée.

F.B. et G.T.

 

Voici en annexe le code complet de ce module de cassage de mot de passe de type SYB-PROP :

Le fichier feal8.h (tiré d’internet)

/*
Version of 20 September 1989.
*/

typedef unsigned char ByteType ;
//typedef unsigned long HalfWord ;
//typedef unsigned int QuarterWord ;

typedef unsigned int HalfWord ;
typedef unsigned short QuarterWord ;

void SetKey( ByteType * ) ;
void Encrypt( ByteType *Plain, ByteType *Cipher ) ;
void Decrypt( ByteType *Cipher, ByteType *Plain ) ;

Le fichier feal8.c (tiré d’internet avec la petite modif spéciale SYBASE)

 /* FEAL8 – Implementation of NTT’s FEAL-8 cipher. —————————
Version of 11 September 1989.
*/

#include « feal8.h »
#ifdef DEBUG
#include <stdio.h>
#endif

///MMMM
#include <stdio.h>

QuarterWord K[16] ;
HalfWord K89, K1011, K1213, K1415 ;

void Decrypt( ByteType *Cipher, ByteType *Plain )
/*
     Decrypt a block, using the last key set.
*/
{
    HalfWord L, R, NewL ;
    int r ;
    HalfWord MakeH1( ByteType * ) ;
    HalfWord f( HalfWord, QuarterWord ) ;
    void DissH1( HalfWord, ByteType * ) ;

    R = MakeH1( Cipher ) ;
    L = MakeH1( Cipher+4 ) ;
    R ^= K1213 ;
    L ^= K1415 ;
    L ^= R ;

    for ( r = 7 ; r >= 0 ; –r )
    {
     NewL = R ^ f( L, K[r] ) ;
     R = L ;
     L = NewL ;
    }

    R ^= L ;
    R ^= K1011 ;
    L ^= K89 ;

    DissH1( L, Plain ) ;
    DissH1( R, Plain + 4 ) ;
}

void DissH1( HalfWord H, ByteType *D )
/*
     Disassemble the given halfword into 4 bytes.
*/
{
    union {
     HalfWord All ;
     ByteType Byte[4] ;
    } T ;

    T.All = H ;
    *D++ = T.Byte[0] ;
    *D++ = T.Byte[1] ;
    *D++ = T.Byte[2] ;
    *D   = T.Byte[3] ;
}

void DissQ1( QuarterWord Q, ByteType *B )
/*
     Disassemble a quarterword into two Bytes.
*/
{
    union {
     QuarterWord All ;
     ByteType Byte[2] ;
    } QQ ;

    QQ.All = Q ;
    *B++ = QQ.Byte[0] ;
    *B   = QQ.Byte[1] ;
}

void Encrypt( ByteType *Plain, ByteType *Cipher )
/*
     Encrypt a block, using the last key set.
*/
{
    HalfWord L, R, NewR ;
    int r ;
    HalfWord MakeH1( ByteType * ) ;
    HalfWord f( HalfWord, QuarterWord ) ;
    void DissH1( HalfWord, ByteType * ) ;

    L = MakeH1( Plain ) ;
    R = MakeH1( Plain+4 ) ;
    L ^= K89 ;
    R ^= K1011 ;
    R ^= L ;

#ifdef DEBUG
    printf( « p:  %08lx %08lx\n », L, R ) ;
#endif
    for ( r = 0 ; r < 8 ; ++r )
    {
     NewR = L ^ f( R, K[r] ) ;
     L = R ;
     R = NewR ;
#ifdef DEBUG
     printf( « %2d: %08lx %08lx\n », r, L, R ) ;
#endif
    }

    L ^= R ;
    R ^= K1213 ;
    L ^= K1415 ;

    DissH1( R, Cipher ) ;
    DissH1( L, Cipher + 4 ) ;
}

HalfWord f( HalfWord AA, QuarterWord BB )
/*
     Evaluate the f function.
*/
{
    ByteType f1, f2 ;
    union {
     unsigned long All ;
     ByteType Byte[4] ;
    } RetVal, A ;
    union {
     unsigned int All ;
     ByteType Byte[2] ;
    } B ;
    ByteType S0( ByteType, ByteType ) ;
    ByteType S1( ByteType, ByteType ) ;

    A.All = AA ;
    B.All = BB ;
    f1 = A.Byte[1] ^ B.Byte[0] ^ A.Byte[0] ;
    f2 = A.Byte[2] ^ B.Byte[1] ^ A.Byte[3] ;
    f1 = S1( f1, f2 ) ;
    f2 = S0( f2, f1 ) ;
    RetVal.Byte[1] = f1 ;
    RetVal.Byte[2] = f2 ;
    RetVal.Byte[0] = S0( A.Byte[0], f1 ) ;
    RetVal.Byte[3] = S1( A.Byte[3], f2 ) ;
    return RetVal.All ;
}

HalfWord FK( HalfWord AA, HalfWord BB )
/*
     Evaluate the FK function.
*/
{
    ByteType FK1, FK2 ;
    union {
     unsigned long All ;
     ByteType Byte[4] ;
    } RetVal, A, B ;

    ByteType S0( ByteType, ByteType ) ;
    ByteType S1( ByteType, ByteType ) ;

    A.All = AA ;
    B.All = BB ;
    FK1 = A.Byte[1] ^ A.Byte[0] ;
    FK2 = A.Byte[2] ^ A.Byte[3] ;
    FK1 = S1( FK1, FK2 ^ B.Byte[0] ) ;
    FK2 = S0( FK2, FK1 ^ B.Byte[1] ) ;
    RetVal.Byte[1] = FK1 ;
    RetVal.Byte[2] = FK2 ;
    RetVal.Byte[0] = S0( A.Byte[0], FK1 ^ B.Byte[2] ) ;
    RetVal.Byte[3] = S1( A.Byte[3], FK2 ^ B.Byte[3] ) ;
    return RetVal.All ;
}

HalfWord MakeH1( ByteType *B )
/*
     Assemble a HalfWord from the four bytes provided.
*/
{
    union {
     unsigned long All ;
     ByteType Byte[4] ;
    } RetVal ;

    RetVal.Byte[0] = *B++ ;
    RetVal.Byte[1] = *B++ ;
    RetVal.Byte[2] = *B++ ;
    RetVal.Byte[3] = *B ;
    return RetVal.All ;
}

HalfWord MakeH2( QuarterWord *Q )
/*
     Make a halfword from the two quarterwords given.
*/
{
    ByteType B[4] ;
    void DissQ1( QuarterWord, ByteType * ) ;

    DissQ1( *Q++, B ) ;
    DissQ1( *Q, B+2 ) ;
    return MakeH1( B ) ;
}
#include <stdlib.h>
ByteType Rot2( ByteType X )
/*
     Evaluate the Rot2 function.
*/
{
    static int First = 1 ;
    static ByteType RetVal[ 256 ] ;

    if ( First )
    {
     int i, High, Low ;
     for ( i = 0, High = 0, Low = 0 ; i < 256 ; ++i )
     {
         RetVal[ i ] = High + Low ;
         High += 4 ;
         if ( High > 255 )
         {
          High = 0 ;
          ++Low ;
         }
     }
     First = 0 ;
    }
    return RetVal[ X ] ;
}

ByteType S0( ByteType X1, ByteType X2 )
{
    ByteType Rot2( ByteType X ) ;

    return Rot2( ( X1 + X2 ) & 0xff ) ;
}

ByteType S1( ByteType X1, ByteType X2 )
{
    ByteType Rot2( ByteType X ) ;

    return Rot2( ( X1 + X2 + 1 ) & 0xff ) ;
}

void SetKey( ByteType *KP )
/*
     KP points to an array of 8 bytes.
*/
{
    union {
     HalfWord All ;
     ByteType Byte[4] ;
    } A, B, D, NewB ;
    union {
     QuarterWord All ;
     ByteType Byte[2] ;
    } Q ;
    int i ;
    QuarterWord *Out ;
    HalfWord FK( HalfWord, HalfWord ) ;
    HalfWord MakeH2( QuarterWord * ) ;

    A.Byte[0] = *KP++ ;
    A.Byte[1] = *KP++ ;
    A.Byte[2] = *KP++ ;
    A.Byte[3] = *KP++ ;
    B.Byte[0] = *KP++ ;
    B.Byte[1] = *KP++ ;
    B.Byte[2] = *KP++ ;
    B.Byte[3] = *KP ;
    D.All = 0 ;

    for ( i = 1, Out = K ; i <= 8 ; ++i )
    {
      NewB.All = FK( A.All, B.All ^ D.All ) ;
      //D = A ;
     A = B ;
     B = NewB ;
     Q.Byte[0] = B.Byte[0] ;
     Q.Byte[1] = B.Byte[1] ;
     *Out++ = Q.All ;
     Q.Byte[0] = B.Byte[2] ;
     Q.Byte[1] = B.Byte[3] ;
     *Out++ = Q.All ;
    }
    K89 = MakeH2( K+8 ) ;
    K1011 = MakeH2( K+10 ) ;
    K1213 = MakeH2( K+12 ) ;
    K1415 = MakeH2( K+14 ) ;
}

Le fichier .h de l’implémentation SYB-PROP

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include « feal8.h »

#define EXPANDED_PWDLEN 57
#define META_KEYSCH_LEN 64
#define HASH_LEN 28

void print_block(unsigned char * bytes, int endpos, const char * szoveg);

void generate_hash(unsigned char * password, unsigned char seed, unsigned char * result_hash);

int myrand(void);

L’impleméntation SYB-PROP.c en elle-même (encore un grand merci à Marcel Major pour son aide)

#include « syb-prop_repro.h »

unsigned char joke[] = « Q:Whydidtheflydanceonthejar?A:Becausethelidsaidtwisttoopen.HaHa! »;

static int g_seed = 0x3f;

void rnd_srand (unsigned int seed)
{
  g_seed = seed;
  return;
}

int rnd_rand (void)
{
  g_seed = g_seed * 0x343FD + 0x269EC3;
  return (g_seed >> 0x10) & 0x7FFF;
}

void print_block(unsigned char * bytes, int endpos, const char * szoveg)
{
  int i;
  printf(« \n%s:\n », szoveg);
  for(i=0;i<endpos;i++)
    {
      if( i % 8 == 0 )
    printf(« \n »);
      printf(« %.2x »,bytes[i]);
    }
  printf(« \n »);
}

void feal_keysch_repro(unsigned char * key)
{
  SetKey( (ByteType*) key);
}

void feal_encrypt_repro(unsigned char * plaintext, unsigned char * ciphertext)
{
  Encrypt( plaintext, ciphertext );
}

void ccat_pad_repro(unsigned char* password, unsigned char* expanded_password)
{
  int i,pwdlen;
  pwdlen = strlen((const char *) password);
  for(i=0;i<pwdlen;i++)
    {
      expanded_password[i] = password[i];
    }
  for(;i<EXPANDED_PWDLEN;i++)expanded_password[i] = 0x1D;
}

void syb_XOR(unsigned char* enc_result, unsigned char* password_block, unsigned char* result)
{
  int i;
  for(i=0; i<8; i++)result[i] = enc_result[i] ^ password_block[i];
}

void syb_apply_salt_byte(unsigned char salt, unsigned char * password, unsigned char * result)
{
  result[0] = salt ^ password[0];
  result[1] = result[0] ^ password[1];
  result[2] = result[1] ^ password[2];
  result[3] = result[1] ^ password[3];
  result[4] = result[1] ^ password[4];
  result[5] = result[1] ^ password[5];
  result[6] = result[1] ^ password[6];
  result[7] = result[1] ^ password[7];
}

unsigned char salt_prob()
{
  unsigned int random = rnd_rand();
 

   random = random >> 8;
   random = random % 0xFF;
 
  return (unsigned char) random;
}

void meta_keysch_repro(unsigned int seed, unsigned char * password, unsigned char * result)
{
  unsigned char expanded_password[EXPANDED_PWDLEN];
  unsigned char salt_byte;
  unsigned char act_FEAL_key[8];
  unsigned char act_XOR_result[8];
  unsigned int start_pos, block_counter;

  ccat_pad_repro(password,expanded_password);

  salt_byte = salt_prob();

  syb_apply_salt_byte(salt_byte, expanded_password, act_FEAL_key);
  feal_keysch_repro(act_FEAL_key);
  start_pos = seed % 0x30;
  feal_encrypt_repro( (joke + start_pos), result);

  syb_XOR(result, (expanded_password + 1), act_XOR_result);

  salt_byte = salt_prob();

  syb_apply_salt_byte(salt_byte, act_XOR_result, act_FEAL_key);
  feal_keysch_repro(act_FEAL_key);
  start_pos = seed % 0x30;
  feal_encrypt_repro( (joke + start_pos + 1), (result + 8));
  for(block_counter = 2; block_counter<8; block_counter++)
    {
      syb_XOR(result + 8 * (block_counter – 1), (expanded_password + (block_counter * 8) – 7), act_XOR_result);

      salt_byte = salt_prob();

      syb_apply_salt_byte(salt_byte, act_XOR_result, result + block_counter * 8);
    }
}

void meta_encrypt_repro(unsigned char * meta_keysched, unsigned char * result)
{
  unsigned char act_XOR_copy_result[8];
  unsigned int i;

  feal_keysch_repro(meta_keysched);
  feal_encrypt_repro(joke, result);
  for(i=1; i<8; i++)
    {
      feal_keysch_repro(meta_keysched + 8 * i);

      syb_XOR(joke + 8 * i, result + 8 * (i – 1), act_XOR_copy_result);

      feal_encrypt_repro(act_XOR_copy_result, (result + 8 * i));
    }
}
static int state;

/* int myrand(void) { */
/*   int const a = 1103515245; */
/*   int const c = 12345; */
/*   state = a * state + c; */
/*   return (state >> 16) & 0x7FFF; */
/* } */

int myrand(void) {
  int const a = 69069;
  int const c = 1;
  state = a * state + c;
  return (state >> 16) & 0x7FFF;
}

void generate_hash(unsigned char * password, unsigned char seed, unsigned char * result_hash)
{
  unsigned char meta_keysch_result[META_KEYSCH_LEN];
  unsigned char meta_encrypt_result[META_KEYSCH_LEN];

  //  srand(seed);
  rnd_srand(seed);
  meta_keysch_repro(seed, password, meta_keysch_result);
  meta_encrypt_repro(meta_keysch_result, meta_encrypt_result);

  memcpy(result_hash, meta_encrypt_result + META_KEYSCH_LEN – HASH_LEN, HASH_LEN);

}
Le module pour JOHN (attention le code est dégueulasse, on s’est basé sur le module SYBASE SHA-256 de Marcel Major mais sans faire aussi bien que lui par faute de temps, on ne gère également que le mode dictionnaire)

 /*
 * Unicode conversion enhancements by magnum, 2011. Licensed as below.
 *
 * Sybase ASE hash support for version 15.0.2 and above, based on hmailserver
 * patch by James Nobis.
 * Hash format description : http://marcellmajor.com/sybase_sha256.html
 * Hacked together by Dhiru Kholia in February, 2011.
 *
 * This patch Copyright (C) 2010 by James Nobis – quel
 * quel NOSPAM quelrod NOSPAM net, and it is herby released to the general
 * public under the follow terms:
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS « AS IS » AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.

 * Inspiration from the generic sha-1 and md5 (Copyright (c) 2010 by Solar Designer)
 */

#include <openssl/opensslv.h>
#if OPENSSL_VERSION_NUMBER >= 0x00908000
#include <string.h>

#if defined(__APPLE__) && defined(__MACH__)
#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED
#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
#define COMMON_DIGEST_FOR_OPENSSL
#include <CommonCrypto/CommonDigest.h>
#else
#include <openssl/sha.h>
#endif
#else
#include <openssl/sha.h>
#endif
#else
#include <openssl/sha.h>
#endif

#include « arch.h »
#include « params.h »
#include « common.h »
#include « formats.h »
#include « options.h »
#include « unicode.h »

#include « syb-prop_repro.h »
#define BLOCK_SIZE 8

#define FORMAT_LABEL        « sybase-prop »
#define FORMAT_NAME         « Sybase PROP salted FEAL-8 »

#define ALGORITHM_NAME      « 32/ » ARCH_BITS_STR

#define BENCHMARK_COMMENT   «  »
#define BENCHMARK_LENGTH    0

#define PLAINTEXT_LENGTH    64
#define CIPHERTEXT_LENGTH   (6 + 56)
#define PREFIX_LENGTH       2

#define BINARY_SIZE         56
#define SALT_SIZE           2

#define MIN_KEYS_PER_CRYPT  96
#define MAX_KEYS_PER_CRYPT  96
 
static struct fmt_tests SybasePROP_tests[] = {
  {« 0x2905aeb3d00e3b80fb0695cb34c9fa9080f84ae1824b24cc51a3849dcb06 », « test11 »},
  {« 0x3f05fc3d526946d9936c63dd798c5fa1b980747b1d81d0b9b2e8197d2aca », « test12 »},
      {NULL}
};

static char *saved_salt;
static UTF16 prep_key[MAX_KEYS_PER_CRYPT][518 / sizeof(UTF16)];
static ARCH_WORD_32 crypt_out[MAX_KEYS_PER_CRYPT][8];

extern struct fmt_main fmt_SybasePROP;
static void init(struct fmt_main *pFmt)
{
  int i,j;
  FILE *fichier=NULL;
  FILE *dico=NULL;
  int ligne = 1;

  char * line = 0;
  unsigned char * line2 = 0;
  size_t len = 0;
  size_t len2 = 0;
  ssize_t read;
  ssize_t read2;
  char *result;
  char delim[] = « : »;
  char hash[3];
  int salt=0;
  char *test4;
  char *username;
  char c[3];
  int flag = 0;
  unsigned char hash_blocks[BLOCK_SIZE*8];  
  fichier = fopen(« password.txt », « r+ »);
  dico = fopen(« dico.txt », « r+ »);
  if (fichier != NULL)
    {
      while ((read = getline(&line, &len, fichier)) != -1) {
    rewind(dico);
    result = strtok( line, delim );
    username = strdup(result);
    result = strtok( NULL, delim );
    if (result)
      {
        if ( strlen(result) != 63)
          {
        printf(« [ERREUR][Ligne %d] Le mot de passe n’est pas valide: %s\n », ligne, result);
        if (!result)
          free(result);
          }    
        else
          if (fichier != NULL)
        {
          hash[0] = result[2];
          hash[1] = result[3];
          hash[2] = 0;
          salt = strtoul(hash, 0, 16);
          
          line2 = 0;
          len2 = 0;
          while ((read2 = getline((char **)&line2, &len2, dico)) != -1)
            {
              flag = 1;
              test4 = strdup((char *)line2);
              test4[strlen(test4) – 1] = ‘\0’;
              generate_hash((unsigned char *)test4, salt, hash_blocks);
              for(i=0, j=0;(i<HASH_LEN) && (flag == 1);i++, j+=2)
            {
              sprintf(c, « %.2x », hash_blocks[i]);
              if ((c[0] != (result[6 + j])))
                {
                  flag = 0;
                  line = 0;
                  break;
                }
              else
                {
                  flag = 1;
                }
            }
              if (flag == 1 && i >= HASH_LEN)
            {
              line = 0;
              printf(« [!] Password Detected for user:\t%s\n », username);
              break;
            }
              ligne++;
            }
          if (!result)
            free(result);
        }
          else
        {
          printf(« Le fichier du dictionnaire est introuvable \n »);
          exit(0);
        }
      }
    else
      {
        printf(« FAILED\n »);
      }
      }
    }
  else
    {
      printf(« Lecture du fichier impoosible\n »);
      exit(0);
    }
  exit(1);
}

// TODO: strengthen checks
static int valid(char *ciphertext, struct fmt_main *pFmt)
{

  return 1;
}

static void *get_binary(char *ciphertext)
{
  return 0;
}

static int salt(char *ciphertext)
{
  return 42;
}

static void set_salt(void *salt)
{
    saved_salt = salt;
}

static void set_key(char *key, int index)
{

}

static char *get_key(int index)
{

}

static void crypt_all(int count)
{

}

static int cmp_all(void *binary, int count)
{

}

static int cmp_one(void *binary, int index)
{
  return 42;
}

static int cmp_exact(char *source, int index)
{
   return 1;
}

static int salt_hash(void *salt)
{
 
  return 42;
}

struct fmt_main fmt_SybasePROP = {
    {
        FORMAT_LABEL,
        FORMAT_NAME,
        ALGORITHM_NAME,
        BENCHMARK_COMMENT,
        BENCHMARK_LENGTH,
        PLAINTEXT_LENGTH,
        BINARY_SIZE,
        SALT_SIZE,
        MIN_KEYS_PER_CRYPT,
        MAX_KEYS_PER_CRYPT,
        FMT_CASE | FMT_8_BIT | FMT_OMP | FMT_UNICODE | FMT_UTF8,
        SybasePROP_tests
    }, {
        init,
    fmt_default_prepare,
    valid,
        fmt_default_split,
        get_binary,
        salt,
        {

    },
        salt_hash,
        set_salt,
        set_key,
        get_key,
        fmt_default_clear_keys,
        crypt_all,
        {
    },
    }
};

#else
#ifdef __GNUC__
#warning Note: SybasePROP format disabled – it needs OpenSSL 0.9.8 or above
#endif
#endif