# m0leCon CTF 2020 Teaser - play-me-piano
>###### tags: `wasm`
>[name=whysw@PLUS]
## Attachments
- problem
- [index.html](https://gist.github.com/YangSeungWon/3de1311c1e03195577f4f52bae76dd02/index.html)
- [chall.js](https://gist.github.com/YangSeungWon/3de1311c1e03195577f4f52bae76dd02/chall.js)
- [chall.wasm](https://gist.github.com/YangSeungWon/3de1311c1e03195577f4f52bae76dd02/chall.wasm)
- writeup
- [chall.c](https://gist.github.com/YangSeungWon/3de1311c1e03195577f4f52bae76dd02/chall.c)
- [chall.h](https://gist.github.com/YangSeungWon/3de1311c1e03195577f4f52bae76dd02/chall.h)
- [main.c](https://gist.github.com/YangSeungWon/3de1311c1e03195577f4f52bae76dd02/main.c)
- [chall](https://gist.github.com/YangSeungWon/3de1311c1e03195577f4f52bae76dd02/chall)
- [sol.py](https://gist.github.com/YangSeungWon/3de1311c1e03195577f4f52bae76dd02/sol.py)
Attachments are uploaded on [gist](https://gist.github.com/YangSeungWon/3de1311c1e03195577f4f52bae76dd02).
## Challenge
https://challs.m0lecon.it:8005/
![](https://i.imgur.com/vHu8V9E.png)
When each button is pressed, review('*what you pressed*') is called.
If it is long pressed, review('-') is also called.
## Solution
### Make ELF binary file in order to analyze in IDA
$ ./wasm2c chall.wasm --no-debug-names -o chall.c
Modified address of `wasm-rt.h` in `chall.h` to absolute path.
Made `main.c` file to compile.
```c:main.c=1
int main(int argc, char* argv[]){
return 0;
}
```
$ gcc chall.c ~/tools/wabt/wasm2c/wasm-rt-impl.c main.c -o chall
now we have ELF binary file.
---
### Static Analysis
pseudo code
```c:pseudocode=
int data[98] = {
0x2a, 0x39, 0x67, 0x7e, 0x71, 0x2d, 0x21, 0x21, 0x72, 0x43, 0x41, 0x3a,
0x09, 0x0c, 0x04, 0x05, 0x52, 0x42, 0x40, 0x19, 0x0a, 0x77, 0x51, 0x42,
0x05, 0x23, 0x36, 0x5b, 0x0c, 0x67, 0x66, 0x22, 0x00, 0x4b, 0x27, 0x38,
0x47, 0x72, 0x6e, 0x5b, 0x75, 0x2b, 0x2c, 0x32, 0x5e, 0x53, 0x47, 0x5a,
0x22, 0x70, 0x74, 0x6d, 0x7b, 0x00, 0x77, 0x68, 0x61, 0x74, 0x27, 0x73,
0x20, 0x74, 0x68, 0x69, 0x73, 0x3f, 0x00, 0x7a, 0x7a, 0x7a, 0x2e, 0x2e,
0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x68, 0x78, 0x20,
0x2e, 0x2e, 0x2e, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x2e, 0x2e, 0x2e,
0x00, 0x2a,
};
int cnt = 0;
char f5(char arg){
cnt++;
data[97] = arg ^ data[cnt] ^ data[97];
return data[97];
}
status review(char input){
char res = f5(input);
if(cnt-1 < 4){
if(data[48+cnt] == res){
return keepgoing;
}else{
data[97] = 0x2a;
cnt = 0;
return fail;
}
}
if(res > 0x7f){
data[97] = 0x2a;
cnt = 0;
return fail;
}
if(cnt == 47){
if(res == '}'){
return success;
}
else{
return fail;
}
}
return keepgoing;
}
```
---
### Brute Forcing...?
I made python code that do brute force... but we can know if these notes are right when all 48 notes are set.
So we can know first 4 notes only: CCGG
### Google knows everything
![](https://i.imgur.com/z2MZ4eL.png)
WOW!
so the answer is ... `ccggaag-ffeeddc-ggffeed-ggffeed-ccggaag-ffeeddc-`
```py:sol.py=
data = [0x2a, 0x39, 0x67, 0x7e, 0x71, 0x2d, 0x21, 0x21, 0x72, 0x43, 0x41, 0x3a, 0x09, 0x0c, 0x04, 0x05, 0x52, 0x42, 0x40, 0x19, 0x0a, 0x77, 0x51, 0x42, 0x05, 0x23, 0x36, 0x5b, 0x0c, 0x67, 0x66, 0x22, 0x00, 0x4b, 0x27, 0x38, 0x47, 0x72, 0x6e, 0x5b, 0x75, 0x2b, 0x2c, 0x32, 0x5e, 0x53, 0x47, 0x5a, 0x22, 0x70, 0x74, 0x6d, 0x7b, 0x00, 0x77, 0x68, 0x61, 0x74, 0x27, 0x73, 0x20, 0x74, 0x68, 0x69, 0x73, 0x3f, 0x00, 0x7a, 0x7a, 0x7a, 0x2e, 0x2e, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x68, 0x78, 0x20, 0x2e, 0x2e, 0x2e, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x2e, 0x2e, 0x2e, 0x00, 0x2a]
cand = "cdefgab-"
cnt = 0
def f5(arg):
global cnt
cnt += 1;
data[97] = ord(arg) ^ data[cnt] ^ data[97]
return data[97]
def review(pressed):
cnt_ = cnt
res = f5(pressed)
if cnt_ < 4:
if data[49+cnt_] == res:
return res
else:
return False
if cnt_ == 47:
if res == ord('}'):
return res
else:
return False
return res
flag = ""
for note in "ccggaag-ffeeddc-ggffeed-ggffeed-ccggaag-ffeeddc-":
res = review(note)
flag += chr(res)
print(flag)
```
output : `ptm{7w1nKl3_7W1NkL3_My_w3b_574r_w3lL_Pl4y3d_hKr}`