Some Assembly Required 1 picoCTF 2021 Solution

Published: April 2, 2026

Description

What can you do with a file that has been WebAssembly compiled? Find the flag on the website.

Remote

Open the challenge URL in your browser.

bash
# 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.

Walk me through it
  1. Step 1
    Find and download the WASM binary
    Observation
    I noticed the challenge mentioned WebAssembly compilation and pointed to a live website, which suggested the flag-checking logic was shipped as a .wasm binary 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 .wasm URL. If no .wasm request appears, search the page source (Ctrl+U) for data:application/wasm or 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('...')) or WebAssembly.instantiate(buffer) - the first argument is the URL of the WASM binary. Alternatively, search the page source for .wasm to find the filename directly.

  2. Step 2
    Decompile the WASM to WAT text format
    Observation
    I noticed the downloaded .wasm file was a compiled binary, which suggested using wasm2wat from 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):
    bash
    sudo apt install wabt   # or download from github.com/WebAssembly/wabt
    bash
    bash
    wasm2wat xSAR1.wasm -o xSAR1.wat
    bash
    grep 'picoCTF{' xSAR1.wat
    bash
    # 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.wasm to extract the flag directly from the binary without installing WABT.

    The strings tool extracts consecutive printable ASCII bytes, but WASM data section strings are often embedded in a length-prefixed format that breaks naive ASCII scanning. strings may output many fragments of WASM section headers and function names but miss or truncate the flag. wasm2wat parses the binary format correctly and emits data segments as proper quoted string literals, making the flag visible to grep.

    Tried: Using wasm2wat without the -o flag and piping directly to grep: wasm2wat xSAR1.wasm | grep 'picoCTF{'.

    Without -o filename, wasm2wat writes 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.wat is 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 data segments 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 .rodata section 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.

Key takeaway

WebAssembly is a compilation target, not a security boundary. String constants embedded in the original source survive into the binary's data section exactly as they were written, making them extractable with the same strings or grep workflow used on any native binary. The sandboxing guarantee of WASM (isolating the module from the OS) is entirely separate from its transparency to static analysis, and tools like wasm2wat produce a lossless textual reconstruction of the full module.

Related reading

Want more picoCTF 2021 writeups?

Useful tools for Web Exploitation

What to try next