# BambooFox CTF 2021 - The Vault

Given a webpage displaying a keypad `index.html`, javascript driver file
`main.js` and webassembly compiled binary `wasm`, you are supposed to find the
pin that unlocks the vault.

## Blackbox approach

Without dealing with the wasm binary at first, reading through `main.js`
specifically between lines 18 and 25 there seems to be some environment
validations and checks.  
```javascript  
var ENVIRONMENT_IS_WEB = false;  
var ENVIRONMENT_IS_WORKER = false;  
var ENVIRONMENT_IS_NODE = false;  
var ENVIRONMENT_IS_SHELL = false;  
ENVIRONMENT_IS_WEB = typeof window === 'object';  
ENVIRONMENT_IS_WORKER = typeof importScripts === 'function';  
ENVIRONMENT_IS_NODE = typeof process === 'object' && typeof process.versions
=== 'object' && typeof process.versions.node === 'string';  
ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE &&
!ENVIRONMENT_IS_WORKER;  
```

Which lead me to think, possibly the driver code `main.js` supports multiple
environments, indeed running the code with `nodejs` yields the banner.

```  
kaftejiman:~/rev/vault/upload  
▶ node main.js  
WASM VAULT v0.1  
```  
which comes from:

```javascript  
function banner() {  
console.log("%c WASM VAULT v0.1", "font-weight: bold; font-size: 50px;color:
red; text-shadow: 3px 3px 0 rgb(217,31,38) , 6px 6px 0 rgb(226,91,14) , 9px
9px 0 rgb(245,221,8) , 12px 12px 0 rgb(5,148,68) , 15px 15px 0 rgb(2,135,206)
, 18px 18px 0 rgb(4,77,145) , 21px 21px 0 rgb(42,21,113)")  
}  
```

knowing `_validate` is the bridge function to the checking routine in the wasm
binary:  
```javascript  
var _validate = Module["_validate"] = function () {  
return (_validate = Module["_validate"] = Module["asm"]["n"]).apply(null,
arguments)  
};  
```  
for the sake of carrying purely a black box approach, we can simply try to
bruteforce all possible combinations (supposed 4 characters long) by slightly
modifying the `main.js` code, specifically:

* modifying banner function to make it call the checking routine  
* modifying fail function to make it less verbose (simply null it)  
* modifying get_password function to make it read pin from argv

```javascript  
function banner() {  
console.log('trying: '+process.argv[2]);  
_validate();  
}

function fail() {  
}

function get_password() {  
const val = process.argv[2];  
const len = lengthBytesUTF8(val) + 1;  
const str = _malloc(len);  
stringToUTF8(val, str, len);  
return str  
}

function win(flag) {  
console.log('found');  
console.log(`${UTF8ToString(flag)}`);  
}  
```

with some bash wrapper (albeit naive algorithm):  
```bash  
for i in `seq 040 177`  
do  
for j in `seq 040 177`  
do  
for k in `seq 040 177`  
do  
for l in `seq 040 177`  
do  
c1=$(printf "\\\$(printf %o $i)\n")  
c2=$(printf "\\\$(printf %o $j)\n")  
c3=$(printf "\\\$(printf %o $k)\n")  
c4=$(printf "\\\$(printf %o $l)\n")  
node main.js "${c1}${c2}${c3}${c4}"  
done  
  
done  
  
done  
  
done  
```

let it spin, after a while you get:  
```  
▶ ./xx.sh  
.  
.  
.  
.  
trying: p/k0  
trying: p0k0  
trying: p1k0  
trying: p2k0  
trying: p3k0  
found  
flag{w45m_w4sm_wa5m_wasm}  
```

## White box approach

From the `main.js` specifically `_evaluate()` calling `Module["asm"]["n"]` we
can deduce `n()` is probably the checking routine in the wasm binary.

Using wasm-decompile from [wabt](https://github.com/WebAssembly/wabt)

```c++  
▶ wasm-decompile main.wasm | grep -A28 'function n'  
export function n() {  
var c:int;  
var a:{ a:long, b:long, c:long, d:short } = g_a - 32;  
g_a = a;  
var b:{ a:ubyte, b:ubyte, c:ubyte, d:ubyte } = a_d();  
a.d = d__WD_l4GoR[12]:ushort;  
a.c = d__WD_l4GoR[2]:long;  
a.b = d__WD_l4GoR[1]:long;  
a.a = d__WD_l4GoR[0]:long;  
if (f_h(b) != 4) goto B_b;  
if (b.a != 112) goto B_b;  
if (b.b != 51) goto B_b;  
if (b.c != 107) goto B_b;  
if (b.d != 48) goto B_b;  
var d:int = 22;  
var e:int = a;  
loop L_c {  
e[0]:byte = (b + (c & 3))[0]:ubyte ^ d;  
e = a + (c = c + 1);  
d = e[0]:ubyte;  
if (d) continue L_c;  
}  
a_c(a);  
goto B_a;  
label B_b:  
a_b();  
label B_a:  
g_a = a + 32;  
}  
```

with:  
* a_d() reads pin  
* a_c() spits flag  
* a_b() fail  
* f_h() sort of checksum maybe?

deduced from:  
```javascript  
var asmLibraryArg = {  
'e': banner,  
'a': _emscripten_resize_heap,  
'b': fail,  
'd': get_password,  
'c': win  
};  
```

`var b:{ a:ubyte, b:ubyte, c:ubyte, d:ubyte } = a_d();`

b populated with pin: {a: 1st char, b:2nd char, c:3rd char, d:4th char}

actual pin check is carried here:  
```  
if (b.a != 112) goto B_b;  
if (b.b != 51) goto B_b;  
if (b.c != 107) goto B_b;  
if (b.d != 48) goto B_b;  
```  
evaluate:  
```  
kaftejiman:RE/rev master ✔ 4d  
▶ pypy3  
Python 3.6.9 (2ad108f17bdb, Apr 07 2020, 02:59:05)  
[PyPy 7.3.1 with GCC 7.3.1 20180303 (Red Hat 7.3.1-5)] on linux  
Type "help", "copyright", "credits" or "license" for more information.  
>>>> chr(112)+chr(51)+chr(107)+chr(48)  
'p3k0'  
```  
try it:

```  
▶ node main.js p3k0  
trying: p3k0  
found  
flag{w45m_w4sm_wa5m_wasm}  
```

done.

Original writeup
(https://gist.github.com/kaftejiman/f416305857a297fb49a35f2c07976f06).Original writeup (https://dystopia.sg/zh3r0-CTF-2021-the-vault/).