>/posts/KPMG2024 JS Task $
Estimated reading time: 9 minutes
JS Task
Category: Web
Difficulty: This could be your first CTF task.
Author: KPMG
Tags: JS, WEB
Description:
In today's world, you can't do without JS.
Do you know the flag?
Handout files
There were no files attached, just a simple form on the website, but I'll try to recreate it with slightly changed values.
Get Familiar with the Task
In the first step, you have to figure out what the main task in this challenge is. As you may see, there is a text input form that updates the textContent depending on a strange-looking if statement. If you can manage to make this if statement evaluate to true, you'll know that your input-flag is correct.
But wait, how are you supposed to know the flag without any additional hints?
Yeah, that's the main part – you have to know JavaScript.
Find the Task Code
If you still don't know how to find the code responsible for changing textContent, follow the screenshots below.
Inspect the text input.
Go to the event listener and click on the referring link.
Now you can see the code responsible for the entire challenge, and luckily, the code is not obfuscated.
Great!
Understanding the Code Logic
const riddle = document.querySelector('#js-riddle');
if (riddle) {
const input = document.querySelector('input');
const log = document.getElementById('values');
const encodedStr1 = 'WTB1X0FyM19DbDBzZV9UMF9G';
const encodedStr2 = 'Z3VyM18wdXRfVGgzX0FuJHdlcg==';
function Random(seed) {
value = seed * 23 % 163;
return value;
}
input.addEventListener('input', updateValue);
function updateValue(e) {
var str = e.target.value;
if (str == atob(encodedStr1).concat(Random(78).toString(), atob(encodedStr2))) {
log.textContent = 'Flag correct!';
} else {
log.textContent = 'Flag incorrect!';
}
}
}
This is nearly the original code with small changes, as I mentioned before.
Ok, so what does it do?
It initializes two strange-looking string variables. Then it compares the input value to those two strings and some random number after every input change. If you haven't seen anything similar before, it may look like just a bunch of random characters, but it's not. The double equal sign (==) suggests it's a Base64 encoded string. The fact that the atob function mentioned in the code above decodes Base64, according to documentation, confirms this.
Oh no, does that mean it's encrypted and we need to decrypt it?
Luckily, no. Just because you can't read it as it is doesn't mean computers can't either. You can think of it as similar to the Roman numeral system. The number MDCCXXIV may look strange at first glance, but you should be able to read it without any special passwords. It's just 1724, spelled using different symbols than usual. If you're still curious about it, Gynvael Coldwind has written a great post about Base64 encoding.
A great tool for decoding this kind of stuff (and a million other things) is CyberChef. If you're willing to learn more and take part in other CTFs, you definitely need to get familiar with this tool. Just paste the text you want to decode and use one of the hundreds of operations – this time fromBase64 will be enough.
Once you've converted the two strings to regular ASCII, we can move forward and see what this if statement really does. It uses the concat function on the first decoded string and adds the second string to it.
Is it really that simple?
Well, not entirely. It also adds a number generated by a function called Random.
Oh no, are we supposed to guess the numbers now?
Of course not! Look at the definition of this function. It performs some operations on the given parameter.
$$ x = seed \times 23 \bmod{163} $$
If you're not sure what the percent sign, aka modulo operation, does, you can check out my previous post about it.
Now you can see that the operation above is not random at all. It may look like it is if you base your judgment only on the returned values, but they are clearly predictable, and with the same seed, it will always return the same value, which is not a characteristic of a random function.
In this case
$$ x = 78 \times 23 \bmod{163} $$ $$ x = 1 $$
This means that 78 is the modular multiplicative inverse of 23 with respect to the modulus 163.
Now we have all the pieces required to solve the atob(encodedStr1).concat(Random(78).toString(), atob(encodedStr2)) string.
Many paths
But wait, this is not the only good solution for this challenge. Once you have the entire JS task code, you can edit it directly in your browser, even if it has already been loaded on the page. Just remember to hit Ctrl + S to save changes. Your browser will create a temporary file for each website with the changes you make. For this challenge, you don't need to follow all the previous steps we've discussed, but it's good to know what's happening in them. To evaluate the if statement to true, you can cut the right-hand side of the equation, assign it to a variable, and then simply print it in the console to see the correct answer independent of the given input value.
var flag = atob(encodedStr1).concat(Random(78).toString(), atob(encodedStr2));
console.log(flag);
Now you can just copy the correct flag from the console and enter it into the form.
So?
Do you know the flag?