Tags: aes wasm 

Rating: 4.5

Solved by: krystalgamer

# WASM(nasm) Fans Only

### Requirements

- wabt - (wasm2c) converts wasm to c
- c compiler
- chromium based browser (couldn't get it to work on firefox)
- disable any script/ad-blocker since it may block the wasm file
- decompiler (not necessary but helpful)

### verifyFlag.js

Analyzing the file there's two interesting functions: `lose` and `win`.

Set a breakpoint on `lose` and press login. According to call-stack it was called from the wasm module, more precisely the `verify_flag` function.

If the call to `function23` returns 0 then it doesn't even go into the big loop.

### Deep diving

Download the wasm module run:
`wasm2c verifyFlag.was -o converted.c`
Converted module dependecy: https://github.com/WebAssembly/wabt/blob/master/wasm2c/wasm-rt.h
`cc -c converted.c`

#### function23

Calls `function25` and checks whether the result is 24. After that goes into a loop and checks for character `'}'`.

#### function25 (strlen)

Starts by checking memory alignment of the passed `ptr` and if it finds any zero byte, quits immiediatelly returning 0.
Then it goes into a loop, incrementing a pointer, and performing this check: `v - UINT64_C(0x0101010101010101)) & ~(v) & UINT64_C(0x8080808080808080);`, which is a zero byte checker, used as a `strlen` performance enhancement. It then returns `ptr-argument`. It's a `strlen`.

Conjugating this knowledge, this function must be checking the structure of the data passed. 24 characters and ending with a `'}'` -> `utflag{16_chars_here}`.

### Backtracking `lose` calls

Besides the one mentioned above there's another one, that is called in a tight loop check.
return lose()

Two buffers are being compared, the result of `function9` and another that was already in memory in position `5245584`(the encrypted flag!).

#### function9

The real name of this function is `aes_encrypt_block` and takes three arguments. `(buffer_to_encrypt, key, output_buffer)`.
The `buffer_to_encrypt` is a ptr to the password field, starting after the `'{'`, the key is `nasmfans.ga` and the output_buffer is `5245568` (contiguous to the encrypted flag!).

#### Encrypted flag

Having the key `nasmfans.ga` and the encrypted key `[15, 174, 248, 89, 132, 177, 40, 103, 40, 24, 136, 23, 100, 211, 37, 42]`. We can just decrypt it.

from Crypto.Cipher import AES

encrypted = [15, 174, 248, 89, 132, 177, 40, 103, 40, 24, 136, 23, 100, 211, 37, 42]

key = bytearray()

for c in 'nasmfans.ga':

while len(key) != 16:

cipher = AES.new(bytes(key), AES.MODE_ECB)

enc_buffer = bytearray()
for e in encrypted:


Which yields `fPRv38aICAz31Ix7`. The flag is `utflag{fPRv38aICAz31Ix7}`

Feel free to reach out to me for any questions.

##### Final notes on function10

I can't leave without talking about this piece of shit, that took me a lot of time to understand. It just converts an array to a matrix. For some reason I thought the name `aes` was just to troll...

aaSSfxxxMarch 9, 2020, 6:04 p.m.


I used a very similar approach, except I compiled with `-m32 -fno-PIC -O2 -c -fno-reorder-functions -fno-inline-functions-called-once -fno-inline-small-functions` in order to simplify most of useless variables (and tweaked the get_intXX/set_intXX to have direct x-refs to data in IDA instead of computing offsets manually).

Nice writeup :)