HackIt! 2013. Level 5. Cifrado casero

crackle Nos pasan un archivo .rar con la contraseña del nivel 5 cifrada. Descomprimiendo el rar nos encontramos con una estructura de archivos como la siguiente:

entregable-dificil/
└── bin
    └── org
        └── euskal
            └── hackit
                ├── _2013
                │   ├── App.class
                │   ├── PasswordReveal.clazz
                │   ├── prepare
                │   │   └── PrepareHackit2013.class
                │   ├── TestClass1.class
                │   ├── TestClass1.clazz
                │   ├── TestClass2.class
                │   └── TestClass2.clazz
                └── crypt
                    ├── CryptUtil.class
                    └── FileClassLoader.class

Los .class los podemos intentar descompilar con jd-gui para ver qué hacen. Por ejemplo, App.class descompilado tiene esta pinta:

public class App
{
  public static void main(String[] args)
    throws Exception
  {
    ((Runnable)new FileClassLoader("bin", new CryptUtil(
      PasswordReveal.daKey), new String[] { "PasswordReveal", "TestClass1", 
      "TestClass2" }).loadClass(
      "org.euskal.hackit._2013.PasswordReveal").newInstance()).run();
  }
}

La clase FileClassLoader carga a partir del directorio pasado como primer parámetro las clases compiladas pasadas en el array de Strings (en el ejemplo PasswordReveal, TestClass1 y TestClass2) y las cifra con la clase CryptUtil (a la que pasa como parámetro una semilla que recoge del atributo estático PasswordReveal.daKey), dejando el resultado en un fichero con el mismo nombre y extensión .clazz.

Los TestClass1 y TestClass2 nos los dan como ejemplo, pero casualmente falta PasswordReveal.class 🙂 que parece ser que es la clase que contiene el password que nos interesa. Lo que sí tenemos es la clase cifrada PasswordReveal.clazz.

Si pudiéramos descifrarla, estaríamos muy cerca de pasarnos el nivel… De hecho, tenemos el .class de CryptUtil. Si lo descompilamos, encontraremos el método de cifrado (ojo, applyCript es el código descompilado y como tal tiene algunos errores fáciles de solucionar manualmente):

public class CryptUtil
 
 public static final long DA_2012_KEY = 4919L;
 static final long a = 1664525L;
 static final long c = 1013904223L;
 static final char m = ' ';
 long seed;
 long initial_seed;
 
 public CryptUtil(long seed)
 {
   this.seed = seed;
   this.initial_seed = seed;
 }
 
 public void applyCrypt(byte[] data)
 {
   this.seed = this.initial_seed;
   for (int i = 0; i < data.length; i++) {
     this.seed = ((1664525L * this.seed + 1013904223L) % 32L);
     byte mask = (byte)(int)(this.seed & 0xFF);
     int tmp46_45 = i;
     byte[] tmp46_44 = data; tmp46_44[tmp46_45] = ((byte)(tmp46_44[tmp46_45] ^ mask));
   }
 }

Parece que applyCrypt básicamente realiza un XOR entre el contenido del .class y una semilla pasada como parámetro. Supuestamente, si cogemos por ejemplo TestClass1.class y le aplicamos applyCrypt, deberíamos obtener TestClass1.clazz (y viceversa, al ser una simple función XOR!). Habrá que comprobarlo…

Deja una respuesta

Tu dirección de correo electrónico no será publicada.

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.