Xmas-Rootme - (03) Generous Santa
25/12/2024Day 3 !!! here we get a web game and need to beat a incredibly high score
Day 3 !!! here we get a web game and need to beat a incredibly high score
Today's challenge was a fun one, we have a web game :
We need to catch as many gifts as possible and at the end, there is a scoreboard with all the best scores.
Of course by the time I write the write up many incredibly funny people put their score 🥸 but initially only Santa's score was really high and playing the game legitimately barely gives you 900 points (trust me I did a lot of attemps 🤓)
First intuiton was to look at the network request made to update the score and just change the score in it.
Unfortunately the data is encrypted and not encoded so we cannot just change it and send it. Lets take a look at the code and try to see how it works. The js file is only 16 000 so it shouldn't be so long to read 😢. Fortunately for us, only the sent data interest us so we just need to look at the fetches of the code (and there is only 4 of them 🥳).
async function Vd(e, t) { const { checksum: r, salt: n } = $d(e, t); const l = Wd({ playerName: e, score: t, checksum: r, salt: n }); try { return await( await fetch( '/api/scores', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ data: l }) } ) ).json() } catch (i) { return console.error('Error submitting score:', i), { success: !1 } } }
This function is the function that interest us since it is the one sending the results. The username and score are passed to the Wd function together with a checksum and salt generated from the $d function, let's take a look at them.
Ud = 'S4NT4_S3CR3T_K3Y_T0_ENCRYPT_DATA'; function Wd(e) { const t = JSON.stringify(e); return gf.AES.encrypt(t, Ud).toString() } function $d(e, t) { const r = Math.floor(Math.random() * 9) + 1, n = `${ e }-${ t }-${ r }`; return { checksum: gf.SHA256(n).toString(), salt: r } }
Bingo, we have everything we need, the encryption key, the salt generator, and the checksum generator. Now we just need to change the t value (score) before sending and send the score. To do so I just put a breakpoint before Wd(), to make sure all the imports and variables are up to date, and then paste this code in the console.
function Wd(e) { const t = JSON.stringify(e); return gf.AES.encrypt(t, 'S4NT4_S3CR3T_K3Y_T0_ENCRYPT_DATA').toString() } function $d(e, t) { const r = Math.floor(Math.random() * 9) + 1, n = `${ e }-${ t }-${ r }`; return { checksum: gf.SHA256(n).toString(), salt: r } } async function Vd(e, t) { const { checksum: r, salt: n } = $d(e, t); const l = Wd({ playerName: e, score: t, checksum: r, salt: n }); try { return await( await fetch( '/api/scores', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ data: l }) } ) ).json() } catch (i) { return console.error('Error submitting score:', i), { success: !1 } } } Vd("atalata", 9999999).then(data => console.log(data));
And we get a response with the flag :)