Home AngstromCTF 2023 Writeups for web exploitation Part 1
Post
Cancel

AngstromCTF 2023 Writeups for web exploitation Part 1

Hello everyone!, here is my writeup for angstromCTF 2023 which ended 2 days ago, sadly I couldn’t participate in it and I solved those challenges after the competition is over :( Let’s dive into it!

1. Catch me if you can


DifficultyPointDownloadable files
1/1010 ptnone

Challange description

Somebody help!

Solution


So looking at the website we can see that there is this long box spinning like crazy with the flag in it

img

It would be annoying to try and catch it manually to copy it, lets’s view the page source!

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
38
<html>
    <head>
        <style>
            body {
                font-family: "Comic Sans MS", "Comic Sans", cursive;
            }
            #flag {
                border: 2px solid red;
                position: absolute;
                top: 50%;
                left: 0;
                -moz-user-select: -moz-none;
                -khtml-user-select: none;
                -webkit-user-select: none;
                -ms-user-select: none;
                user-select: none;

                animation-name: spin;
                animation-duration: 3000ms;
                animation-iteration-count: infinite;
                animation-timing-function: linear; 
            }

            @keyframes spin {
                from {
                    transform:rotate(0deg);
                }
                to {
                    transform:rotate(360deg);
                }
            }
        </style>
    </head>
    <body>
        <h1>catch me if you can!</h1>
        <marquee scrollamount="50" id="flag">actf{y0u_caught_m3!_0101ff9abc2a724814dfd1c85c766afc7fbd88d2cdf747d8d9ddbf12d68ff874}</marquee>
    </body>
</html>

And down there you get the flag!

Learned: Inspect source code

2. Celeste Speedrunning Association


DifficultyPointDownloadable files
2/1020 ptnone

Challange description

I love Celeste Speedrunning so much!!! It’s so funny to watch!!!
Here’s my favorite site!

Solution


Looking at the homepage of the challenge we see a scoreboard for some kind of speedrun and there is 0 second record that we should beat somehow

img

Let’s navigate to the /play route!

img

So the challenge is to press this button very fast I think, let’s try pressing it

img

Sadge, We couldn’t beat the old lady:( let’s look at the source code for the button

1
2
3
4
5
6
<form action="/submit" method="POST">
  <input type="text" style="display: none;" value="1682640324.9098408" name="start" />
  <input type="submit" value="Press when done!" />
</form>

So the button does a POST request to this /submit URL with an argument called start, and it sends this weird number, huh? A very big number that is time hmmm?… Oh, it is epoch time! epoch time is the time in seconds that elapsed since the dawn of Unix time at 00:00:00 UTC on 1 January 1970, It’s stored in a 32-bit signed variable and it’s the representation of date&time in computers, you can read more about it at this wikipedia page

So since we can modify this value using burp suite, let’s navigate to /play and press the button with burp suite interception turned on, and we would capture this request

img note that the start value will be different for you depending on when you view the challenge The way the record is measured is probably that it compares the value of the start parameter and its current epoch time, so if we send a value in the future by sending a larger number than the one in the start parameter, it would result in a negative record, and we would be the first in the leaderboard!

And indeed by sending a larger value, we got the flag!

img

Learned: Epoch time, Burp suite intercept

Due to epoch time being stored in a signed 32-bit variable, when this variable reaches the maximum value it can hold (2^31 - 1 = 2147483647), which will happen at 03:14:07 UTC on 19 January 2038, the integer will overflow! and that will cause the date to go all the way back to 20:45:52 UTC on 13 December 1901!!, you can read more about this Year 2038 problem .

3. Shortcircuit


DifficultyPointDownloadable files
3/1040 ptnone

Challange description

Bzzt

Solution


going into the website we see this basic login form shortcircuit login page

let’s view the source code

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<html>
    <head>
        <title>Short Circuit</title>

        <script>
            const swap = (x) => {
                let t = x[0]
                x[0] = x[3]
                x[3] = t

                t = x[2]
                x[2] = x[1]
                x[1] = t

                t = x[1]
                x[1] = x[3]
                x[3] = t

                t = x[3]
                x[3] = x[2]
                x[2] = t

                return x
            }

            const chunk = (x, n) => {
                let ret = []

                for(let i = 0; i < x.length; i+=n){
                    ret.push(x.substring(i,i+n))
                }

                return ret
            }

            const check = (e) => {
                if (document.forms[0].username.value === "admin"){
                    if(swap(chunk(document.forms[0].password.value, 30)).join("") == "7e08250c4aaa9ed206fd7c9e398e2}actf{cl1ent_s1de_sucks_544e67ef12024523398ee02fe7517fffa92516317199e454f4d2bdb04d9e419ccc7"){
                        location.href="/win.html"
                    }
                    else{
                        document.getElementById("msg").style.display = "block"
                    }
                }
            }
        </script>
    </head>
    <body>
        <form>
            <input name="username" placeholder="Username" type="text" />
            <input name="password" placeholder="Password" type="password" />

            <input type="button" onclick="check()" value="Log in"/>
        </form>
        <p id="msg" style="display:none;color:red;">Username or password incorrect</p>
    </body>
</html>

So we see that the flag is there but it isn’t formatted, Analysing the check() function, we see it checks if the user name is admin checks if the swap of chunking the password value is equal to the flag text

Looking at the chunk() function and we find that it splits any string it gets every n value, so if we gave it the flag text as implemented it splits it every 30 characters to form 4 “chunks”, splitting it nicely like this

1
2
>> chunk("7e08250c4aaa9ed206fd7c9e398e2}actf{cl1ent_s1de_sucks_544e67ef12024523398ee02fe7517fffa92516317199e454f4d2bdb04d9e419ccc7",30)
Array(4) [ "7e08250c4aaa9ed206fd7c9e398e2}", "actf{cl1ent_s1de_sucks_544e67e", "f12024523398ee02fe7517fffa9251", "6317199e454f4d2bdb04d9e419ccc7" ]

Now looking at the swap() function, It basically swaps the first element with the fourth one, then swaps the second and the third, then the second and the fourth, and lastly the third and the fourth, now this causes headage so look at this diagram

Diagram for how swap fucntion works debugging of swap() function

So if you understand it correctly, you will notice that double swapping the flag text would make the actf{ part at the beginning and } one at the ending

1
2
3
4
5
6
7
8
>> flagText = "7e08250c4aaa9ed206fd7c9e398e2}actf{cl1ent_s1de_sucks_544e67ef12024523398ee02fe7517fffa92516317199e454f4d2bdb04d9e419ccc7"
"7e08250c4aaa9ed206fd7c9e398e2}actf{cl1ent_s1de_sucks_544e67ef12024523398ee02fe7517fffa92516317199e454f4d2bdb04d9e419ccc7"

>> swap(swap(chunk(flagText,30)))
Array(4) [ "actf{cl1ent_s1de_sucks_544e67e", "6317199e454f4d2bdb04d9e419ccc7", "f12024523398ee02fe7517fffa9251", "7e08250c4aaa9ed206fd7c9e398e2}" ]

>> swap(swap(chunk(flagText,30))).join("")
"actf{cl1ent_s1de_sucks_544e67e6317199e454f4d2bdb04d9e419ccc7f12024523398ee02fe7517fffa92517e08250c4aaa9ed206fd7c9e398e2}" 

And inputting it into the login form we can verify that is indeed the flag!

Learned: Code auditing

4. Directory


DifficultyPointDownloadable files
3/1040 ptnone

Challange description

This is one of the directories of all time, and I would definitely rate it out of 10.

Solution


Looking at the homepage we see there are huuuuuge number of links to other pages

directory homepage

let’s try and open one of them

directory page 0

So the flag is in one of those links LOL, and we have to scan ALL OF THEM ONE BY ONE

so there are 2 ways to solve this

  1. you get blessed by god and randomly select the right one (very easy but not for everyone :)
  2. you run some sort of brute forcing method to scan all those directories

The one I did is using burp suite intruder, let’s try that, first let’s capture a GET request to one of those pages, Send it to the intruder and select the number in the URL and add it

Capturing request brupsuite

Select sniper attack, go to the payload, select numbers payloads type, change the starting and ending point (0-4999), and start the attack

brupsuite intruder

As you can see all the requests are resulting in code 200, then how would we know the right one? we can know that by looking at the response length since all the pages have the exact message on them except that page that has the flag!

brupsuite intruder attack setting

After some good time, I found the flag at page /3054.html, going there and we get the flag!

Getting the flag

When I was looking for how others solve this challenge I found some interesting other ways, one was to download all those pages and do a grep search on them (shout out to SloppyJoePirates), another way I found by dimasma0305 is to use python request with multithreader to speed up the process.

Learned: Requests brute-forcing, Burp suite intruder


To be continued in part 2!

This post is licensed under CC BY 4.0 by the author.

CTF tricks for web expliotation

AngstromCTF 2023 Writeups for web exploitation Part 2

Comments powered by Disqus.