jueves, 29 de agosto de 2013

RDG Simple Crackme .NET

Aquí esta mi solución para el RDG Simple Crackme .NET, un crackme muy sencillo, ya que RDGMax nos ayuda con un botón "Sample Serial" que nos muestra el serial para su usuario y esto facilita las cosas.  Por ejemplo, la solución es trivial si la longitud del nombre de usuario es menor o igual a seis caracteres, pues basta con cambiar el binario en un editor hexadecimal, buscando la cadena en unicode "RDGMax" Y cambiándola por el valor que deseemos :P



Si la longitud es mayor, nos encontramos con cierta ofuscación, pero usando de4dot se remueve sin problemas y podemos pasar a inspeccionar el binario ya limpio en .NET Reflector.

Desde el Reflector, podríamos ir a WindowsApplication1.Form2 y usar Reflexil para parchar el valor del TextBox1.Text en la funcion InitializeComponent().  Con Reflexil ya no tenemos el limite de seis caracteres y el binario modificado funciona.

Sin embargo, ya estando aqui, y siendo tan fácil con un parche, decidimos mas bien escribir un generador de claves.  Para estudiar la rutina de generación basta con mirar la funcion Button1_Click() en el WindowsApplication1.Form1:

private void Button1_Click(object sender, EventArgs e)
{
    clsx clsx = new clsx();
    MyProject.Forms.Form2.Show();
    clsx.K = Conversions.ToString((long) ((((((((((((((((this.xa() + this.xb()) - this.xb()) + this.xa()) + this.xa()) - this.xb()) - 100L) + 0x34L) + this.xb()) - this.xa()) + this.xb()) + this.xb()) - this.xa()) + this.xa()) - this.xa()) - this.xa()) + this.xb()));
    this.t2.Text = this.Sth(clsx.Se(this.t1.Text));
}

La clase clsx() suministra el servicio de cifrado DES, ese clsx.K es un valor intermedio usad para el calulo de la clave de cifrado, y clsx.Se() es la rutina encargada de cifrar cadenas de texto. Podemos ver que clsx.K se calcula desde xa() y xb(), estas simplemente hacen algunas operaciones matematicas y retornan un flotante cada una.  Despues de todos lso calculos clsx.K = "5167449".  Finalmente, Sth() es solo una conversion de string a hexstring.

En el set_K() de la clase clsx(), podemos ver como se genera la clave:

public void set_K(string value)
{
...
        encoding.GetBytes(value, charIndex, value.Length, bytes, charIndex);
...
        byte[] buffer2 = new SHA1CryptoServiceProvider().ComputeHash(bytes);
        charIndex = 0;
        do
        {
            this.TheKey[charIndex] = buffer2[charIndex];
            charIndex++;
        }
        while (charIndex <= 7);
...
}

Allí vemos que TheKey se calcula desde el hash SHA1 de los bytes en clsx.K, para obtener la clave de cifrado.  Después del proceso, TheKey = {0xd4, 0xed, 0x34, 0x93, 0x1c, 0x48, 0xac, 0x08}, asi que usaremos directamente este valor en el keygen.

Ahora veamos la función de cifrado:

public string Se(string strSource)
...
        CryptoStream stream2 = new CryptoStream(stream, this.objDES.CreateEncryptor(this.TheKey, this.Vector), CryptoStreamMode.Write);
stream2.Write(bytes, 0, bytes.Length);
        stream2.FlushFinalBlock();
        str = Convert.ToBase64String(stream.ToArray());
...
    return str;
}

Allí vemos como el cifrador retorna codificado en base64, y encontramos una referencia al Vector que contiene el IV.  Los valores del IV los encontraremos en el constructor de la clase:

public clsx()
{
    this.Vector = new byte[] { 0x12, 0x44, 0x16, 0xee, 0x88, 0x15, 0xdd, 0x41 };
...
}

Usando estos trozos de código como base, pero asignando directamente el valor a TheKey, logre escribir este trozo de C#, y verificar que funcionaba usando un compilador online de C#:

using System.Security.Cryptography;
using System.IO;
using System.Text;
using System;

class Program
{
    static void Main()
    {
        byte[] TheKey = { 0xd4, 0xed, 0x34, 0x93, 0x1c, 0x48, 0xac, 0x08 };
        byte[] Vector = { 0x12, 0x44, 0x16, 0xee, 0x88, 0x15, 0xdd, 0x41 };
        byte[] bytes = Encoding.UTF8.GetBytes("rmolina");
        MemoryStream stream = new MemoryStream();
        DESCryptoServiceProvider objDES = new DESCryptoServiceProvider();
        CryptoStream stream2 = new CryptoStream(stream, objDES.CreateEncryptor(TheKey, Vector), CryptoStreamMode.Write);
        stream2.Write(bytes, 0, bytes.Length);
        stream2.FlushFinalBlock();
        string str = Convert.ToBase64String(stream.ToArray());
        foreach(char ch in str)
            Console.Write("{0:X}", Convert.ToUInt32(ch));
    }
}

Finalmente, escribí mi generador de claves en python, usando el PyDes de Todd Whiteman:

from pyDes import *
from base64 import b64encode
TheKey = b"\xd4\xed\x34\x93\x1c\x48\xac\x08"
Vector = b"\x12\x44\x16\xee\x88\x15\xdd\x41"
k = des(TheKey, CBC, Vector, padmode=PAD_PKCS5)
Username = input("Name: ")
d = b64encode(k.encrypt(Username))
print("Serial: " + "".join('%02X' % i for i in d))

Aquí están algunas de las salidas:
_
C:\Python33>python.exe RDG_Simple_Crackme.py
Name: RDGMax
Serial: 456D455A6866384A304E343D

C:\Python33>python.exe RDG_Simple_Crackme.py
Name: rmolina
Serial: 7942596B573755696550553D

C:\Python33>python.exe RDG_Simple_Crackme.py
Name: Ruben Molina
Serial: 347661484671357363615337496B4B517644694231773D3D

Las verificamos y todas son correctas :)


Y eso es todo por hoy :)

No hay comentarios:

Publicar un comentario