Search code examples
javascriptobfuscationreverse-engineeringxordeobfuscation

Understanding complicated javascript password algorithm


this is a javascript exercise, I need to know what is the correct password. Can you understand it? it drives my nuts!

Do I need to compare the value against some generated bytecode?

I think when the right password guessed "Congratz!" messages will pop.

<script type="text/javascript">
</script>
Password: <input /><br />
<button>Check</button>

<script id="urchin">

(function() {
  var h = [
  function() {alert("booo")},
  function() {alert(":(")},
  function() {alert("Congratz!")},
  function() {alert("almost there")},
  function() {alert("alert(b[a]);")},
  function() {alert("nahh")},
  function() {alert("not even close")}
  ]
  var g = function(d) {
    var a, f, e, g, k, b = [];
    for(a = 0;256 > a;a++) {
      b[a] = a
    }
    f = "click"
    e = 0;
    d = "input";
    g = document[("getElementsByTagName")]("input")["0"][("value")];
    for(a = 0;256 > a;a++) {
      e = (e + b[a] + f.charCodeAt(a % f[("length")])) % 256, b[a] ^= b[e], b[e] ^= b[a], b[a] ^= b[e]
    }
    a = e = 0;
    f = "";
    for(k = a;k < g.length;k += 2) {
      a = (a + 1) % 256
      e = (e + b[a]) % 256
      b[a] ^= b[e]
      b[e] ^= b[a]
      b[a] ^= b[e]



      f += String[("fromCharCode")](parseInt(g[("substr")](k, 2), 16) ^ b[(b[a] + b[e]) % 256])
    }
    a = f["charCodeAt"](f[("charCodeAt")](0) % f.length) % 6;
    f != d + 256 && 2 == a && a++;
    h[a]()
  }
  var d = document[("getElementsByTagName")]("button")["0"];
  typeof d.addEventListener != typeof g ? d.attachEvent("onclick", g) : d[("addEventListener")]("click", g, !0);

  d = document[("getElementById")]("urchin");
  d[("parentNode")].removeChild(d);
  c = function() {}
})();
</script>

Solution

  • The correct password is 956918b1820bc657.

    The crackme is essentially RC4.

    The following initializes the RC4 key table, with the key click, storing the result in b:

    var a, f, e, g, k, b = [];
    for(a = 0;256 > a;a++) {
      b[a] = a
    }
    f = "click"
    e = 0;
    d = "input";
    g = document[("getElementsByTagName")]("input")["0"][("value")];
    for(a = 0;256 > a;a++) {
      e = (e + b[a] + f.charCodeAt(a % f[("length")])) % 256, b[a] ^= b[e], b[e] ^= b[a], b[a] ^= b[e]
    }
    

    Encryption/decryption happens next using b, after converting the input from hex, storing the result in f:

    a = e = 0;
    f = "";
    for(k = a;k < g.length;k += 2) {
      a = (a + 1) % 256
      e = (e + b[a]) % 256
      b[a] ^= b[e]
      b[e] ^= b[a]
      b[a] ^= b[e]
      f += String[("fromCharCode")](parseInt(g.substr(k, 2), 16) ^ b[(b[a] + b[e]) % 256])
    }
    

    Finally the decrypted string is compared with input256. a is just a checksum.

    To reverse this process, just encrypt input256 using rc4, then convert it to hex.

    You're welcome to post this to crackmes.de and crackmes.us, and cite where it came from.