Tags: webasm chrome 

Rating:

# Assembly Me (Re)

In the task we get a simple webpage with a single textbox and button.
There is javascript and [webassembly](wasm.txt) code which validates password we input on the page.

There is quite a lot of this webasm, and reversing it is quite hard, but already initial reading shows:

```javascript
var button = document.getElementById('check');

button.addEventListener('click', function(){

u = document.getElementById("i").value;
var a = Module.cwrap('checkAuth', 'string', ['string']);
var b = a(u);
document.getElementById("x").innerHTML = b;
});
```

So we know that entry point is `checkAuth` function, and we can see that:

```
(export "_checkAuth" (func $func35))
```

So let's focus on this single function:

```
(func $func35 (param $var0 i32) (result i32)
(local $var1 i32) (local $var2 i32)
get_global $global5
set_local $var1
get_global $global5
i32.const 16
i32.add
set_global $global5
get_local $var1
set_local $var2
get_local $var0
i32.const 1616
i32.const 4
call $func57
i32.eqz
if
get_local $var0
i32.const 4
i32.add
i32.const 1638
i32.const 4
call $func57
i32.eqz
if
get_local $var0
i32.const 8
i32.add
i32.const 1610
i32.const 5
call $func57
i32.eqz
if
get_local $var0
i32.const 13
i32.add
i32.const 1598
i32.const 4
call $func57
i32.eqz
if
get_local $var0
i32.const 17
i32.add
i32.const 1681
i32.const 3
call $func57
i32.eqz
if
get_local $var0
i32.const 20
i32.add
i32.const 1654
i32.const 9
call $func57
i32.eqz
if
get_local $var1
set_global $global5
i32.const 1690
return
end
end
end
end
end
end
i32.const 1396
get_local $var0
get_local $var0
call $func45
call $func57
i32.eqz
if
get_local $var1
set_global $global5
i32.const 1761
return
end
i32.const 1747
get_local $var2
call $func77
drop
get_local $var1
set_global $global5
i32.const 1761
)
```

Main part of the code is a cascade of conditions and calls to `$func57`.
Once we pass a single condition we can enter another one, so it's safe to assume we need to pass all of them.

Reversing webasm is hard, so first we tried to work with this as some kind of blackbox.
It's clear that before calling function 57 there is some address put on the stack (1616, 1638... are addresses of some strings in the code) and some small number.
We can also see that we want the return value to be 0, so we can pass the condition.
By seding some random values for the first condition we can notice a very interesting characteristic of the return value - it's not random at all.
In fact it's monotonous!
If we send `a` we get value `X`, if we send `b` we get `X+1` etc.
So it's trivial to calculate which character we need to send in order to get `0`.
But once we do this, the value instead of 0 becomes some larger number.
Our guess was that the function checks multiple characters, so once we get a "valid" first character, it checks another one and thus we get a large number again.

With those assumptions the solution seems quite straightforward:

1. We put breakpoint on `i32.eqz`
2. We send random letter as password, let's say `a`.
3. We send next letter in alphabet, to make sure we didn't actually get the right one on first try.
4. Now we know how far `a` is from the expected letter, so we can calculate a real password character by `chr(ord('a')-X)`

We can repeat this with second letter of the password, and so on, until we actually pass the condition.
Once we pass the check (after a few letters), we can place another breakpoint on the next condition and repeat the same procedure.

So for example when we send `a` we get return value (top of the stack) `-3` which means the real character is `chr(ord('a')-(-3) == 'd'`:

![](debug.png)

We follow this approach to get whole password: `d51XPox)1S0xk5S11W_eKXK,,,xie` and we get `Authentication is successful. The flag is NDH{password}`

Original writeup (https://github.com/p4-team/ctf/tree/master/2018-03-30-nuit-du-hack/re_assembly).