Skip to main content

Some Assembly Required 1 picoCTF 2021 Solution

A web challenge where the flag is locked inside a WebAssembly module served by the page.

Published: April 2, 2026Updated: August 13, 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 1Find and download the WASM binary
    Observation
    The challenge mentions WebAssembly compilation and points at a live site. The flag-checking logic ships as a .wasm asset the browser fetches and runs, so the Network tab is where 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 2Decompile the WASM to WAT text format
    Observation
    The downloaded .wasm is a compiled binary. wasm2wat from the WABT toolkit converts it to readable WAT text, which puts any string constants from the data section, the flag included, within reach of 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.

    strings extracts consecutive printable ASCII, but WASM data section strings often sit in a length-prefixed format that breaks naive scanning. You get fragments of section headers and function names while the flag is missed or truncated. wasm2wat parses the binary format properly and emits data segments as quoted string literals, which grep can find.

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

    Without -o, wasm2wat writes to stdout and piping to grep usually works. But if the data section holds non-UTF-8 bytes, the pipe can emit binary noise ahead of the flag line and confuse some terminal encodings. Writing to a file first is safer, and it leaves the full decompiled module available if the grep comes up empty.

    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 from the original source survive into the binary's data section exactly as written, extractable with the same strings and grep workflow you would use on any native binary. WASM's sandboxing, which isolates the module from the OS, is a separate matter from its transparency to static analysis, and wasm2wat reconstructs the full module losslessly as text.

Related reading

Useful tools for Web Exploitation

Where to go next