lundi 11 mars 2013

Prequals NDH 2k13 - Crackme Huge.js

Voici le write-up d'une d'une autre épreuve des prequals de la NDH 2k13.

Description

On nous donne un fichier .js mais assez "huge". Evidemment ca rame à mort si on l'ouvre avec notepad, etc ...

Analyse du script

Donc on l'ouvre avec notre éditeur héxa préféré ou même Chrome et là on découvre :

function d() {
  return (window.console &&
         (window.console.firebug || window.console.exception));
}

function x(c, k) {
  o = '';
  for (i = 0; i < c.length; i++) {
    o += String.fromCharCode(c.charCodeAt(i) ^ k.charCodeAt(i % k.length));
  }
}

On a donc une fonction d(debug) qui check si on debug le script et une fonction x(or) qui déchiffre une string xorée. Dans la suite du code, les strings sont évidemment xorées avec cette fonction.

window[x('\x44\x29\x42\x42','\x21\x5f\x23\x2e\x2b\x28\x3f\x2d')](x('\x42\x4b\x17\x0f\x5b\x01\x08\x02\x56\x48\x47\x51\x4d...));



Déchiffrement

Il suffit donc d'écrire un script qui va remplacer chaque appelle à la fonction "x" par son résultat. A la fin on aura notre fichier Javascript en clair et avec une taille correct !

def xor(c, k):
  return "".join([chr(ord(c[i])^ord(k[i%len(k)])) for i in range(len(c))])


def decode(f):
  data = open("huge.js", "r").read()
  pos = data.find("x('\\", 0)
  while pos != -1:
    sep = data.find(",", pos)
    end = data.find(")", pos)
    c = data[pos+3:sep-1].replace("\\x", "").decode("hex")
    k = data[sep+2:end-1].replace("\\x", "").decode("hex")
    data = data[:pos] + xor(c, k) + data[end+1:]
    pos = data.find("x('\\", 0)
  f = open("result.js", "w")
  f.write(data)
  f.close()

decode("huge.js")

Et oui, on parse à l'ancienne avec des "pos" et des "substrings" !

On obtient une fonction "xxx" qui est en fait un md5, "kkk" qui reverse une string et une fonction "unlock" pour tester le mot de passe :

function unlock(node){
  var code = node.value;
  if (code && (code.length == 5)){
    if ((xxx(code).substr(0,16)=='b3336efd42e29780') &&
        (xxx(kkk(code)).substr(16,16)=='261804c5f2f0a47e')){
      var flag = document.createElement('span');
      var t = document.createTextNode('YAY, you got the flag ! --> '+xxx(code));
      flag.appendChild(t);
      flag.style.font='Helvetica, 1.2em, bold';
      document.getElementById('panel').appendChild(flag);
      node.style.display = 'none';
      node.value = '';
    }
  }
}

Il suffit donc de trouver un pass de 5 caractères dont le début du md5 est "b3336efd42e29780". Bf :

import sys


charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789<>(){}-+"

h = "b3336efd42e29780".decode("hex")


def brute(n, s):
  if n>0:
    for c in charset:
      brute(n-1, s+c)
  else:
    if hashlib.md5(s).digest()[:8] == h:
      print s
      sys.exit(0)

brute(5, "")

Au bout de quelques temps on obtient : i<3Js

Et voilà :)

Aucun commentaire:

Enregistrer un commentaire