# hxp 36C3 CTF - xmas_future >###### tags: `wasm` >[name=whysw@PLUS] ## Attachments - problem - [hxp2019.js](https://gist.github.com/YangSeungWon/080959d7e3d34b4bcdd6c9bc381dca86#file-hxp2019-js) - [ferris.svg](https://gist.github.com/YangSeungWon/080959d7e3d34b4bcdd6c9bc381dca86#file-ferris-svg) - [hxp2019_bg.wasm](https://gist.github.com/YangSeungWon/080959d7e3d34b4bcdd6c9bc381dca86#file-hxp2019_bg-wasm) - [index.html](https://gist.github.com/YangSeungWon/080959d7e3d34b4bcdd6c9bc381dca86#file-index-html) - [run.sh](https://gist.github.com/YangSeungWon/080959d7e3d34b4bcdd6c9bc381dca86#file-run-sh) - [wasm.svg](https://gist.github.com/YangSeungWon/080959d7e3d34b4bcdd6c9bc381dca86#file-wasm-svg) - writeup - [hxp2019_bg.wat](https://gist.github.com/YangSeungWon/080959d7e3d34b4bcdd6c9bc381dca86#file-hxp2019_bg-wat) - [hxp2019_bg.c](https://gist.github.com/YangSeungWon/080959d7e3d34b4bcdd6c9bc381dca86#file-hxp2019_bg-c) - [hxp2019_bg.h](https://gist.github.com/YangSeungWon/080959d7e3d34b4bcdd6c9bc381dca86#file-hxp2019_bg-h) - [main.c](https://gist.github.com/YangSeungWon/080959d7e3d34b4bcdd6c9bc381dca86#file-main-c) - [sol.py](https://gist.github.com/YangSeungWon/080959d7e3d34b4bcdd6c9bc381dca86#file-sol-py) - [xmas_future](https://gist.github.com/YangSeungWon/080959d7e3d34b4bcdd6c9bc381dca86#file-xmas_future)(ELF) Attachments are uploaded on [gist](https://gist.github.com/YangSeungWon/080959d7e3d34b4bcdd6c9bc381dca86). ## Challenge ![](https://i.imgur.com/PXoy05n.png) When you press the *Check* button, `check` function is called and `check` function in wasm is also called. ```javascript:hxp2019.js=66 /** * @param {string} pwd * @returns {bool} */ export function check(pwd) { var ptr0 = passStringToWasm0(pwd, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); var len0 = WASM_VECTOR_LEN; var ret = wasm.check(ptr0, len0); return ret !== 0; } ``` ## Solution ### Dynamic debugging ```wasm:hxp2019_bg.wat=1958 (func $hxp2019::check::h578f31d490e10a31 (;4;) (param $var0 i32) (param $var1 i32) (result i32) (local $var2 i32) (local $var3 i32) (local $var4 i32) (local $var5 i32) (local $var6 i32) (local $var7 i32) (local $var8 i32) (local $var9 i32) (local $var10 i32) get_global $global0 i32.const 32 i32.sub tee_local $var2 set_global $global0 i32.const 0 set_local $var3 block $label0 get_local $var1 i32.const 50 i32.ne br_if $label0 ``` ... ```wasm:hxp2019_bg.wat=2281 end local.get 2 i32.const 32 i32.add global.set 0 local.get 3) ``` $var0 is ptr to input string, and $var1 is length of input string. so flag length must be 50! --- ### make ELF file #### wasm2c $ ~/tools/wabt/build/wasm2c hxp2019_bg.wasm --no-debug-names -o hxp2019_bg.c Outputs are `hxp2019_bg.c` and `hxp2019_bg.h`. For compilation, I fixed relative path of wasm-rt.h in `hxp2019_bg.h` to absolute path. ```c:hxp2019_bg.h=9 #include "/home/whysw/tools/wabt/wasm2c/wasm-rt.h" ``` #### main.c I searched for memory allocation for wasm, and found this one. [Flare-On 5 CTF WriteUp (Part 3)](https://blog.attify.com/flare-on-5-writeup-part3/) ```c:main.c= #include <stdio.h> #include <stdlib.h> #include <string.h> #include "hxp2019_bg.h" int main(int argc, char** argv) { /* Make sure there is only one command-line argument, and length id 50.*/ if (argc != 2) return 1; if (strlen(argv[1]) != 50) return 1; init(); memcpy(&(Z_memory->data[10000]), argv[1], 50); u32 result = Z_checkZ_iii(10000, 50); if(result == 0) printf("fail\n"); else printf("success\n"); return 0; } ``` #### compile $ gcc hxp2019_bg.c ~/tools/wabt/wasm2c/wasm-rt-impl.c main.c -o xmas_future --- ### gdb scripting ![](https://i.imgur.com/Xa8P8AX.png) ![](https://i.imgur.com/hMqm2gI.png) When the input character is different from the flag character, it goes to red block and break. But when it's correct, it goes to green block and continue the loop. It means that if we set a breakpoint at 0x4065B5, the program stops when each character is right. So I decided to do gdb scripting. ```python:sol.py= #!usr/bin/python import gdb import string FILE_NAME = 'xmas_future' BREAK_ADDR = '0x4065B5' LEN = 50 count = 0; class BP_Manager(gdb.Breakpoint): def stop(self): global count count += 1 return; gdb.execute("file {}".format(FILE_NAME)) bp_addr = BP_Manager("*"+BREAK_ADDR) answer = "hxp{,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,}" trial_pos = 4 while trial_pos < LEN-1: for ch in string.digits+string.ascii_letters+'!.,{_/}': count = 0 trial = answer[:trial_pos] + ch + answer[trial_pos+1:] gdb.execute("r $(python -c \"print '{}'\")".format(trial)) if count == trial_pos -4 +1: answer = trial print("FLAG:",answer) trial_pos += 1 break ``` $ gdb -x sol.py output : `FLAG: hxp{merry_xmas___github.com/benediktwerner/rewasm}`