mercredi 4 juillet 2012

NDH 2k12 - Stay Alive - 500 pts

Dernier crackme de cette série de writeup de la NDH 2k12, une application windows phone !

1.       What
On a donc une application Windows phone dans son fichier « xap », en regardant de plus près on voit qu’il s’agit d’un fichier compressé (PK).
On decompresse puis on se retrouve avec les fichiers de l’application :


Si on passe les images, le xaml pour l’interface et le manifest, il reste la dll qui contient le code de l’application, probablement une appli qui demande un mot de passe …
On peut essayer d’ouvrir la dll avec IDA mais on voit rapidement qu’il s’agit de .Net. On switch donc dans notre décompileur de .Net préféré (pour moi Reflector).

private void ndhPasswordLogin_Click(object sender, RoutedEventArgs e)
{
   
string password = this.ndhPassword.get_Password();
   
if (password.Length > 0)
   
{
       
if (string.Equals(this.cryptPassword(password), this.trustedHash()))
       
{
           
base.get_NavigationService().Navigate(new Uri("/LoginError.xaml", UriKind.Relative));
       
}
       
else
       
{
            MessageBox
.Show("Login failed, try again.", "Error", 0);
       
}
   
}
}

On a une fonction qui sera appelé pour vérifier un password. On test si le mot de passe chiffré avec « cryptPassword » correspond au « trustedHash() ». Rien de spécial, continuons …

2.       TrustedHash
Un simple writeLn ou copier/coller et on obtient :

+R2kbpJn0tqCMmUNZzFwQFMU+EW0/Nkoup5Zl4hxoPFRfmk1fhKJhfBkdhNYiDqt23jbRoxDbO3
QHpy6M2kY/8hd3Z1ds8a1StSQkXxNyjZd2mTQPpTR4zmyf9FzK4Y4XUfzw1hUP3qj+dGyKgNjQm
XdtPTOqRVh2T41NSvmK/YV6XzIk6SFdhF9XyXUJOlcII5mXQ/SuHiHmkEoTJiUF3XGN/LkjnNy6pRzZH6s2YC27g7sqqFj71xPY+S3KHLy1y/PwJtz1E7EBzqaXxTxDOE9wiPArIoY9Rl//8RalprwBKeEzZajgbqFz5sEkV6hplGCkiua1FfPXht9Ef8br


3.       CryptPassword

private string cryptPassword(string password)
{
   
string key = "AYOOYOYOAYOOYOYO";
   
string salt = "WOLOLOWOLOLOOOO";
   
string str3 = "ndh2k12!";
   
string str4 = null;
   
string data = null;
   
for (int i = 0; i < password.Length; i++)
   
{
       
string str6 = password[i].ToString();
       
string str7 = null;
       
if ((i % 2) == 0)
       
{
            str7
= this.base64Encode(str3 + str6);
       
}
       
else
       
{
            str7
= this.aesEncode(str6, str4, str3);
       
}
        data
= data + str7;
        str4
= str7;
   
}
   
return this.aesEncode(data, key, salt);
}

On parcours donc notre password, si on est sur un caractère pair on ajoute à « data » base64(ndh2k12 ! + char) sinon on ajoute à « data » le caractère chiffré avec la clé « key »  et le salt « salt ».
A la fin, “data” subit une dernière transformation, aesEncode, toujours avec la même key et salt.

Pourquoi ne pas faire l’inverse !

On part du « trustedHash », on sait qu’en dernier il a été chiffré alors on le déchiffre. On obtient ensuite un certain nombre de blocs suivant la taille du mot de passe hashé.
Pour les blocs pairs, il suffit de le décodé en base64 puis de garder le dernier caractère.
Pour les blocs impairs, il faut le déchiffrer avec le bloc précédent comme clé et toujours le même salt.
Ainsi de suite pour chaque bloc pair et impair …

4.       Résultat
Pour déchiffrer, la fonction s’écrit plus ou moins en copiant la fonction de chiffrement :

private string aesDecode(string data, string key, string salt)
{
   
byte[] bytes = new byte[salt.Length];
    bytes
= Encoding.UTF8.GetBytes(salt);
    Aes aes
= (Aes) new AesManaged();
    aes
.Key = new Rfc2898DeriveBytes(key, bytes).GetBytes(0x10);
    aes
.IV = aes.Key;
    MemoryStream stream
= new MemoryStream();
    CryptoStream stream2
= new CryptoStream(stream, aes.CreateDecryptor(), CryptoStreamMode.Write);
   
byte[] buffer = Convert.FromBase64String(data);
    stream2
.Write(buffer, 0, buffer.Length);
    stream2
.FlushFinalBlock();
   
return Encoding.UTF8.GetString(stream.ToArray());
}

Notre “trustedHash” déchiffré donne :
bmRoMmsxMiFomEpoK3JjVufPG4PHIZOr8A==bmRoMmsxMiF2yXWqntvVZX50EN1IlnTo3w==bmRoMmsxMiF3bZY/Kf1nEbIZJkxufD/aAQ==bmRoMmsxMiFs28dlLHl69r6pmBbjIPgYBw==bmRoMmsxMiEtpGqGLudtlrHht7kVeEfMLA==bmRoMmsxMiFlCW4AQUIJeTVAbcdBXbRDQg==bmRoMmsxMiFlMZm7jEzQutN6OwSAVddgAw==bmRoMmsxMiEtVbvy0FmdISllXQlSmMRR0w==bmRoMmsxMiFpWGsPB3wrW20H79tUp8T47w==

On peut ensuite découper ça en bloc :
bmRoMmsxMiFo
mEpoK3JjVufPG4PHIZOr8A==
bmRoMmsxMiF2
yXWqntvVZX50EN1IlnTo3w==
bmRoMmsxMiF3
bZY/Kf1nEbIZJkxufD/aAQ==
bmRoMmsxMiFs
28dlLHl69r6pmBbjIPgYBw==
bmRoMmsxMiEt
pGqGLudtlrHht7kVeEfMLA==
bmRoMmsxMiFl
CW4AQUIJeTVAbcdBXbRDQg==
bmRoMmsxMiFl
MZm7jEzQutN6OwSAVddgAw==
bmRoMmsxMiEt
Vbvy0FmdISllXQlSmMRR0w==
bmRoMmsxMiFp
WGsPB3wrW20H79tUp8T47w==
 
Le premier bloc décodé donne : ndh2k12!h donc le caractère du passe est : h
Le deuxième bloc déchiffré donne : z
On continue comme ça jusqu’au dernier bloc pour obtenir : hzv-will-never-die

Aucun commentaire:

Enregistrer un commentaire