Reverse engineering, Windows internals, x86 magic, low level programming, and everything else I feel like writing about.

CrySyS SecChallenge 2020: It wasm me, Stardust!

Destroying the Death Star 5/5

Here you are so close to the end. As you initiate the self-destruction, you need to enter a code to verify the action. After that your mission is complete.

Good luck rebels, may the Force be with you.

Categories

Web Security

Files

Solution

From the name and links we can already guess this will be a WebAssembly reversing challenge. Looking at the environment’s source we can quickly find main_bg.wasm. I prefer static analysis over dynamic, so I threw it into a decompiler instead of debugging:

wasm-decompile main_bg.wasm --ignore > dec.txt

In it, we can quickly find the check function and it’s used resources:

global g_a:int = 1050160;

data d_a(offset: 1024) = "haxorinvalid malloc request";

export function check(a:int, b:int):int {
  var c:int = g_a - 32;
  c[3]:long@1 = 1874636579285894411L;
  c[11]:long@1 = 3963455813207921946L;
  c[19]:short@1 = 6404;
  c[21]:long@1 = 805306673345600284L;
  c[29]:short@1 = 5632;
  c[31]:byte = 18;
  var d:int = 0;
  if (b != 29) goto B_a;
  b = 0;
  d = 1;
  loop L_b {
    var e:ubyte_ptr = b / 5;
    if (b > 28) goto B_a;
    var f:ubyte_ptr = a + b;
    e = e * -5 + 1024 + b;
    var g:ubyte_ptr = c + 3 + b;
    b = b + 1;
    if ((e[0] ^ f[0]) == g[0]) continue L_b;
  }
  d = 0;
  label B_a:
  return d;
}

We can easily see the length is checked against 29 (if (b != 29) goto B_a;), then the string iterated over (var f:ubyte_ptr = a + b;) and XORed then the result checked against something ((e[0] ^ f[0]) == g[0]). Fortunately for us, XOR is an associative operation, so we could write the previous line as (e[0] ^ g[0]) == f[0], so this turned into what is essentially a simple string comparison. By printing e[0] ^ g[0] instead of comparing we can easily obtain the flag. I C++ified the code and ran it:

int main()
{
  size_t b = 29;

  char c[29];
  *(int64_t*)(c) = 1874636579285894411L;
  *(int64_t*)(c + 8) = 3963455813207921946L;
  *(int16_t*)(c + 16) = 6404;
  *(int64_t*)(c + 18) = 805306673345600284L;
  *(int16_t*)(c + 26) = 5632;
  *(int8_t*)(c + 28) = 18;
  const static char d_a[] = "haxorinvalid malloc request";

  int d = 0;
  if (b != 29)
    goto B_a;

  b = 0;
  d = 1;
  while(true)
  {
    if (b > 28)
      goto B_a;
    //const auto f = a + b;
    const auto e = (b / 5) * -5 + d_a + b;
    const auto g = c + b;
    b = b + 1;
    /*if ((*e ^ *f) != *g)
      break;*/
    printf("%c", *e ^ *g);
  }
  d = 0;
B_a:
  return d;
}

Output:

cd20{debug_this_easily_i_can}