Description
What can you do with a file that has been WebAssembly compiled? Find the flag on the website.
Setup
Open the challenge URL in your browser.
# Open the challenge URL in your browser with DevTools open (F12)Solution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1
Find and download the WASM binaryObservationI noticed the challenge mentioned WebAssembly compilation and pointed to a live website, which suggested the flag-checking logic was shipped as a.wasmbinary asset that the browser would fetch and execute, making the Network tab the right place to intercept it.Open DevTools > Network and reload. Look for a request with Content-Type application/wasm or a.wasmURL. If no.wasmrequest appears, search the page source (Ctrl+U) fordata:application/wasmor a base64 blob - some pages inline the module instead of fetching it.Learn more
WebAssembly (WASM) is a binary instruction format designed for execution in web browsers alongside JavaScript. It compiles from languages like C, C++, or Rust and runs at near-native speed. WASM modules are fetched over HTTP just like JavaScript files - they appear in the Network tab as requests with Content-Type
application/wasm.Why WASM is used in CTF challenges: Developers sometimes compile validation logic to WASM thinking it is harder to reverse-engineer than JavaScript. In practice, WASM is just as reversible as any compiled binary - the WAT format is a full lossless representation, and tools like Ghidra (with the WASM plugin) or wabt can decompile it entirely. The security model of WASM is about sandboxing (preventing access to the host OS), not obfuscation.
Finding the WASM file if the Network tab is unclear: Look at the page's JavaScript source for calls to
WebAssembly.instantiateStreaming(fetch('...'))orWebAssembly.instantiate(buffer)- the first argument is the URL of the WASM binary. Alternatively, search the page source for.wasmto find the filename directly.Step 2
Decompile the WASM to WAT text formatObservationI noticed the downloaded.wasmfile was a compiled binary, which suggested usingwasm2watfrom the WABT toolkit to convert it to human-readable WAT text so that any string constants (like the flag) stored in the data section would become visible to grep.Use wasm2wat (from the WebAssembly Binary Toolkit, WABT) to convert the binary WASM file to its human-readable WAT (WebAssembly Text Format) equivalent. Search the output for the picoCTF string.bash# Install WABT (WebAssembly Binary Toolkit):bashsudo apt install wabt # or download from github.com/WebAssembly/wabtbashbashwasm2wat xSAR1.wasm -o xSAR1.watbashgrep 'picoCTF{' xSAR1.watbash# If grep finds nothing, the flag is byte-checked rather than stored as a literal -bash# trace the comparison loop in the validation function (see SAR2/SAR3 patterns).Expected output
picoCTF{8857462f...}What didn't work first
Tried: Running
strings xSAR1.wasmto extract the flag directly from the binary without installing WABT.The
stringstool extracts consecutive printable ASCII bytes, but WASM data section strings are often embedded in a length-prefixed format that breaks naive ASCII scanning.stringsmay output many fragments of WASM section headers and function names but miss or truncate the flag.wasm2watparses the binary format correctly and emits data segments as proper quoted string literals, making the flag visible to grep.Tried: Using
wasm2watwithout the-oflag and piping directly to grep:wasm2wat xSAR1.wasm | grep 'picoCTF{'.Without
-o filename,wasm2watwrites to stdout, and piping to grep does work in most cases. However, if the WASM file contains non-UTF-8 bytes in its data section, the pipe may emit binary noise before the flag line that confuses some terminal encodings. Writing to a file first with-o xSAR1.watis safer and lets you inspect the full decompiled module to understand the validation logic if the grep finds nothing.Learn more
WAT (WebAssembly Text Format) is the textual representation of WASM bytecode. It uses S-expression syntax (like Lisp) and is fully reversible from WASM - no information is lost in decompilation. String literals from the original source code are embedded as
datasegments in the WASM binary and appear verbatim in the WAT output.This is a fundamental property of compiled languages: string constants survive compilation. Strings like flag values, error messages, and format strings are stored in the data section of the binary and can be extracted with tools like
strings,wasm2wat, or a hex editor. Always search compiled binaries for string literals before attempting deeper reverse engineering.Structure of a WASM module: A WASM binary is organized into sections: type (function signatures), import (external JS functions the module calls), function (index-to-type mapping), memory (linear memory size), export (functions/memory exposed to JS), code (the actual bytecode), and data (initialized memory content including string literals). The data section is where the flag lives - it is essentially the
.rodatasection of the compiled binary, embedded verbatim in the WASM file.For harder WASM challenges: When the flag is not a simple string constant but is instead computed or compared byte-by-byte, you need to trace the WASM logic. Use the browser's built-in WASM debugger (Chrome DevTools supports WASM breakpoints and DWARF debug info), or load the WASM file in Ghidra with the WASM plugin to get a C-like decompilation of the validation function. Understanding the data flow from user input to the comparison is the same skill as binary reverse engineering.
Interactive tools
- Regex TesterTest regular expressions against a string with live match highlighting, flag toggles, and common CTF pattern shortcuts.
Flag
Reveal flag
picoCTF{8857462f...}
WebAssembly binaries compile to a readable WAT text format - string constants in the original source survive compilation and are visible in decompiled output.