WebAssembly Text (WAT) format through the
wasm2wat tool. This conversion allowed us to ex-
amine the internal memory layout of the module, dis-
covering that the password was stored at the mem-
ory offset 1024. The next phase of our attack strat-
egy focused on obtaining a write primitive, achiev-
able through the format specifier %n. To overwrite the
password at the address 1024, we first need to store
the value 0x400 (1024 in hexadecimal) into a known
offset from the printf pointer. To achieve that, we
craft a payload composed of 1024 characters followed
by %2$n|%p|: given that the offset 2 initially con-
tains the value 0 (Figure 2), this payload will write
the value 0x400 at address 0.
The final step involved writing the ASCII value of
”B” (0x42 in hexadecimal or 66 in decimal) to ad-
dress 1024. This is achieved with a payload formed
by a 66-character sequence followed by %n, thereby
writing 0x42 to the address found at the first offset
(which is 1024), effectively overwriting the password
with the letter ”B”.
After executing this attack and deploying the crafted
payloads, we can bypass the password check by sub-
mitting the character ”B”.
The exploitation process for the server-side appli-
cation is similar to the client-side, with two key dif-
ferences. Firstly, the output of the ‘printf‘ function
is shown on the server console, not in the browser.
This prevents attackers from directly leaking stack
data or accessing the WebAssembly module to locate
the password’s offset. However, overwriting memory
is still possible, and attackers could perform a ”blind”
attack to find the correct offset via brute force. The
second difference is related to the Emscripten version
used. To run a Node.js application that loads Wasm
modules, we needed to upgrade to Emscripten release
3.1.52. After recompiling the C code and converting
the Wasm module to the readable WAT format, we ob-
served a significant shift in the password’s offset from
1024 to 65536, requiring a much larger payload for an
attack.
This information enabled us to craft a payload ca-
pable of writing the value 65536 (0x10000 in hex-
adecimal) into the first offset, allowing us to overwrite
the password at the correct offset. Given the substan-
tial size of this payload, an attacker might encounter
buffer size constraints. A workaround for this issue
involves using the format specifier %65536c, which
prints the specified amount of characters without ex-
ceeding buffer limits.
Contrary to previous works (McFadden et al.,
2018), we successfully exploited the format string
vulnerability within the WebAssembly environment,
managing to overwrite sensitive data in memory. The
predictability of memory address locations in We-
bAssembly, due to the lack of Address Space Lay-
out Randomization (ASLR), considerably facilitates
the exploitation process. In contrast, exploiting envi-
ronments with ASLR is more challenging due to the
randomized memory addresses. This highlights the
importance of addressing memory layout predictabil-
ity in WebAssembly’s modules.
Moreover, we observed that including the %p spec-
ifier is crucial for the payload %2$n|%p to success-
fully write to memory. Although this payload aims to
write to memory using the %n specifier, the %p speci-
fier, typically used for reading data, appears to be nec-
essary for the write operation to proceed. Omitting
the %p specifier results in the payload failing to write
to memory. The exact reasons behind this remain an
area for further investigation, highlighting an intrigu-
ing aspect of format string vulnerabilities within We-
bAssembly.
4.3 Use after Free
In this PoC, we present a server-side application ex-
hibiting a Use After Free (UAF) vulnerability, high-
lighting the dangers associated with heap manage-
ment errors when developing WebAssembly applica-
tions.
4.3.1 Proof of Concept Overview
Before diving into the details of the front-end side of
the application, we focus on a snippet of the vulnera-
ble C code, which can be seen in Listing 3.
Listing 3: Code of the PoC for the Use After Free vulnera-
bility
t y p e d e f s t r u c t {
c h a r a [ 3 0 ] ;
c h a r f l a g [ 5 ] ;
} o b j e c t ;
o b j e c t
*
x ;
b o ol c h e c k p a s s w o r d ( c h ar
*
p a s s ) {
r e t u r n ( s t r c m p ( p a ss , x−> f l a g ) == 0 ) ;
}
v o id i n i t ( ) {
x = m a l l o c ( s i z e o f ( o b j e c t ) ) ;
s t r n c p y ( x−> f l a g , ” wasm ” , 5) ;
}
This code snippet defines a structure named ”ob-
ject”, which has a size of 35 bytes. The init func-
tion dynamically allocates memory for an ”object”
instance, storing its address in the variable ”x” and
initializing the ”flag” field with the string ”wasm”.
However, the check password function compares
this ”flag” field with user input, potentially after its
memory has been freed, thereby introducing a Use
After Free (UAF) vulnerability into the application.
SECRYPT 2024 - 21st International Conference on Security and Cryptography
556