Flare-On 5 CTF WriteUp (Part 3)

. 6 min read

This is part 3 of the Flare-On 5 CTF writeup series.

5 - Web 2.0

The future of the internet is here, again. This next challenge will showcase some the exciting new technologies paving the information super-highway for the next generation.

Similar to the fourth, the fifth challenge is also based on Web technologies - HTML, Javascript and ... Web Assembly (WASM). Web Assembly is quite new and its usage is fairly limited but increasing nevertheless. As its name suggests, WASM allows to execute assembly code on the browser, but it doesn't mean traditional assembly languages like x86, ARM and MIPS we're familiar with. Instead, WASM defines an entirely new binary format with its own instruction set to be run on a stack-based virtual machine in the browser. WASM comes with the promise that it will provide near-native performance as a desktop app running on the user's system.

Let's go back to the challenge. We've three files index.html, main.js and test.wasm. Before WASM can be executed on the browser there are some tasks that must be done beforehand like setting up an interface so that the WASM code can interact with the JS code, setting up arguments for function calls, converting JS values such that WASM can operate on that etc. All of this is done by main.js.


It reads a URL parameter q and converts it to a Uint8Array of bytes. It allocates two 0x200 bytes memory block within the WASM instance. One of them is filled with an array of byte values declared at the start. The other is filled with the bytes of the URL parameter q. Next, it calls a function named Match exported from the WASM code with the proper arguments. It's evident the URL parameter q is the flag. If the function returns 1, our flag is correct.

Analyzing the WASM code in JEB decompiler

JEB decompiler from PNF Software can analyze WASM binaries. The demo version is good enough at least for a basic analysis.


Apart from Match, JEB identified nine other functions from f1 to f9. Besides, there's another function writev_c. Let's have a look at Match.


The signature specifies it takes four i32 parameters and returns an i32 value as output. We already had found out this information by analyzing the JS code. Unlike regular native executables, the WASM binary format also describes the signature and number of local variables of each and every function. For example, Match has 24 locals inclusive of the four parameters. Have a look at this document to know in-depth about the WASM format.

WASM is a stack-based virtual machine like CPython. There are no registers. All operations must be done by pushing and popping values off the stack. For example, adding two numbers is achieved by pushing the values; the i32.add instruction pops off the topmost two values, adds them and pushes the result back on the stack.

For experimenting with Web Assembly, try out WasmExplorer and WebAssembly Studio.

Match calls f9 and based on its return value either returns 1 or 0. So essentially the check is performed in f9.


Using the WebAssembly Binary Toolkit

The WebAssembly Binary Toolkit (WABT) provides several useful tools to work on WebAssembly. Among them is wasm2c which aims to convert a wasm binary to equivalent C source with a header. It is not a true decompiler but rather converts the WASM instructions to equivalent C code.

After running wasm2c on test.wasm, the C code for Match looks like.

static u32 Match(u32 p0, u32 p1, u32 p2, u32 p3) {
  u32 l0 = 0, l1 = 0, l2 = 0, l3 = 0, l4 = 0, l5 = 0, l6 = 0, l7 = 0, 
      l8 = 0, l9 = 0, l10 = 0, l11 = 0, l12 = 0, l13 = 0, l14 = 0, l15 = 0, 
      l16 = 0, l17 = 0, l18 = 0, l19 = 0, l20 = 0, l21 = 0, l22 = 0, l23 = 0;
  u32 i0, i1, i2, i3, i4;
  i0 = g0;
  l0 = i0;
  i0 = 32u;
  l1 = i0;

  i0 = l2;
  i1 = p1;
  i32_store((&memory), (u64)(i0 + 20), i1);
  i0 = l2;
  i1 = p2;
  i32_store((&memory), (u64)(i0 + 16), i1);
  i0 = i32_load8_u((&memory), (u64)(i0 + 11));
  l18 = i0;
  i0 = 1u;
  l19 = i0;
  i0 = l18;
  i1 = l19;
  i0 &= i1;
  l20 = i0;
  i0 = l2;
  i1 = l20;
  i32_store((&memory), (u64)(i0 + 28), i1);
  i0 += i1;
  l23 = i0;
  i0 = l23;
  g0 = i0;
  i0 = l21;
  goto Bfunc;
  return i0;

All assignment and arithmetic operations have been converted to their C equivalent. Additionally, wasm2c introduced some helper functions like i32_load and i32_store since they no C equivalent. However, the code is still far away from being fit for analysis. It would be nice if we can optimize the code.

We don't want to optimize by hand. That's the work of a compiler. However, we need to provide a main function before we can run gcc.


Compiling with we get an x86 ELF. Decompiling the file using HexRays in IDA, f9 looks like


This is a lot better than what we obtained with wasm2c. If we analyze the WASM code of f9 we can see it there's a CALL_INDIRECT instruction. This translates to the following C snippet.


Immediately below there's a comparison between a character of our input to the value calculated by the above indirect function call.


This means if set a breakpoint at this location we may be able to retrieve the flag character by character. However, we need to do this in the WASM code and not in the ELF as the decompiled wasm2c code may not have the exact behaviour as the WASM binary.

Debugging WASM in Firefox

Firefox offers the ability to debug WASM code. First, we need to set up a local web server which can be done using $ python -m SimpleHTTPServer or something like https://github.com/m3ng9i/ran.

With Firefox and the web server setup let's identify the proper location in the WASM code which implements the comparison of the correct byte with that of the flag.

The CALL_INDIRECT instruction is located at B7F.


The comparison instruction must be located after this. Indeed, a few lines below we do find an i32.eq instruction which performs a sign agnostic equality check.


Let's set a breakpoint here and rerun with a known flag as input like


When the breakpoint hits we can see the instruction is essentially comparing the values of var82 and var83 which are loaded on the stack just before. var83 contains 97 (a) the first character of our input. This is being compared to 119 (w). This suggests the first character of the flag is w. Proceeding in the same fashion we can retrieve the entire flag character by character.


FLAG: wasm_rulez_js_droolz@flare-on.com

Continue to the next part: Flare-on 5 CTF Write-up (Part 4)


Reverse Engineer with an interest in low level stuff and anything about security.

Get IoT Security Training

IoT Pentesting Exploitation Training


analog modulation Android android application security android hands on security and exploitation training android security Apktool application auditing application security auditing appsec usa appwatch arduino nano arm ARM binaries ARM course ARM exploitation book ARM exploitation video training ARM gadgets ARM Training attify attify badge attify training best security practices biggest iot attacks of all time binwalk blackberry pentesting blackhat ble BLE attacks BLE dangers BLE hacking and exploitation BLE security issues BLE sniffing BLE vulnerabilities bleah bluetooth technology box brut Exception BtleJuice capture radio traffic career in cybersecurity CCTV cameras challenges in iot retail chroot cloud based mobile application security scanner consulting CTF cyber attacks cybersecurity Damn Vulnerable iOS App dangers of iot DDoS attacks devops digital modulation dumping memory embedded hacking expert Exploit ARM devices exploitation exploiting ble exploiting smart devices firmadyne firmware analysis toolkit firmware emulation Firmware hacking firmware reverse engineering Flare-on frida getting started with firmware hacking ghidra GSMA guide to ARM exploitation hacked security IP cameras hacked smart devices hackers hackfest hacking smart devices healthcare business protection against iot threats healthcare cyber security how can healthcare fight iot threats How Mirai botnet infects your device How Mirai works how retail can prevent cyber attacks how to exploit ble how to hack radio waves how to protect iot devices how to secure iot device IDA internet of things Internet of Things Security internet security ios application security ios security iot iot attacks iot bots, malwares iot device IoT Devices IoT Exploitation iot hacking iot hacks IoT hacks on ARM devices iot penetration testing iot pentest iot pentesting iot security IoT security guidelines iot security training iot threats iot threats to healthcare industry iotsecurity IP cameras jtag jtag debugging latest iot attacks learn ARM exploitation measures to prevent cyber attacks on healthcare organisations Mirai Botnet mirai history mobile app mobile application security mobile application security testing mobile security monitor iot devices Mozilla network security in retail ninja recon technique NIST offensive iot exploitation ola cabs owasp owasp appsec penetration testers penetration testing pentesting pentesting mobile apps phishing attacks powerofcommunity PrinterSecurity privacy protection profession professional qemu quizup radio communication protocol radio coomunication radio waves hacking recent ARM attacks recent cyber attacks recent iot attacks recent security camera attacks retail iot Reversing safety measures to protect privacy sdr secure coding guidelines security security cameras security challenges in retail IoT security in healthcare iot security issue security issues faced by e-retailers security services security training security vulnerability setup smart devices smart user security social networking spi steps to prevent iot attacks on healthcare surveillance cameras hijacked threat modeling tools to exploit ble training uart Understanding Mirai Botnet virus vulnerabilities discovered in popular IoT IP cameras vulnerabilities in internet connected cameras vulnerability vulnerable ARM devices What is mirai botnet? why choose career in cybersecurity writeups xposed hooking zigbee zigbee exploitation zigbee security zwave