WayWitch
WayWitch
CHALLENGE DESCRIPTION
(NOTE: use https:// to connect to the instance)
SOLUTION
By analyzing the source code, we can see that account with admin
username hold the flag.
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
async function generateJWT() {
const existingToken = getCookie("session_token");
if (existingToken) {
console.log("Session token already exists:", existingToken);
return;
}
const randomNumber = Math.floor(Math.random() * 10000);
const guestUsername = "guest_" + randomNumber;
const header = {
alg: "HS256",
typ: "JWT",
};
const payload = {
username: guestUsername,
iat: Math.floor(Date.now() / 1000),
};
const secretKey = await crypto.subtle.importKey(
"raw",
new TextEncoder().encode("halloween-secret"),
{ name: "HMAC", hash: "SHA-256" },
false,
["sign"],
);
const headerBase64 = btoa(JSON.stringify(header))
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=+$/, "");
const payloadBase64 = btoa(JSON.stringify(payload))
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=+$/, "");
const dataToSign = `${headerBase64}.${payloadBase64}`;
const signatureArrayBuffer = await crypto.subtle.sign(
{ name: "HMAC" },
secretKey,
new TextEncoder().encode(dataToSign),
);
const signatureBase64 = btoa(
String.fromCharCode.apply(
null,
new Uint8Array(signatureArrayBuffer),
),
)
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=+$/, "");
const token = `${dataToSign}.${signatureBase64}`;
document.cookie = `session_token=${token}; path=/; max-age=${60 * 60 * 24}; Secure`;
console.log("Generated JWT Session Token:", token);
}
From the code above, we can see the web uses halloween-secret
to generate token.
Inspect the web, we notice the token session, it is a HS256 JWT
. We need to modify it with secret key to generate new token by using JWT
Copy the token and paste to our token, access /tickets
and get the flag.