➜ ~

Playing Hacks and Stuffs!


Project maintained by h4ckyou Hosted on GitHub Pages — Theme by mattgraham

openECSC CTF 2024 ( Round 2)

Good day, here I’ll be giving the writeup to the few challenges I was able to solve during the ctf

Another round, another sanity check

Just the standard “sanity check” challenge, going over to their discord challenge in the “announcement” group gives the flag image

Flag: openECSC{ldepywBS5XUBYHLeVDo6+mK7iFHFhwhwY0+LjR3R9EI=}

Blind Maze

image

We are given a pcap file and after downloading the attachment I opened it up in Wireshark image image

The first noticable thing is that this contains http requests

And on looking at the protocol hierachy shows it contains mostly http request image

Following the tcp stream I saw that it’s basically solving a web based maze challenge where direction start initializes the game and gives us a session cookie and up, down, left & right are the paths used to move around the maze image

At the last http request that is after solving the maze finish the flag is shown to us image

Apparently this didn’t involve us solving it at our end and it turned out to be an unintended solution so they released a revenge sequel of the challenge

Flag: openECSC{i_found_a_map_e1871a60}

Revenge of the Blind maze

image

It’s very identical to the previous one but this time around the flag isn’t in the pcap file meaning we would need to solve it

During the process of trying to solve it I spent quite some time on it because i didn’t bother to understand how the maze worked

Here’s what I did:

This didn’t work then I started debugging

From looking through various packets I concluded that when a user sends a path to the server there’s a possibility of it being not processed which then the user needs to resend the path

Here’s how that failed chance looks here image

So if we get that we then need to resend the path as shown here image

With that said my initial path which I extracted contained repetitive paths i.e the path which are valid and the ones which are repeated again due to failure

In order to extract just the valid path I checked for the case where by the path given fails

With that said it’s then simple to solve

Another thing is that we can get the “failed” message multiple times but that can be easily fixed by just resending the path till it works

Here’s the script I used to extract the paths from the pcap file: extract

import re

def extract_paths(content):
    pattern = r'Last Move: (.+?)</h4>'
    paths = re.findall(pattern, content)
    return paths

def filter_successful_paths(paths):
    return [path for path in paths if "FAILED" not in path]

file = ["response1.txt", "response2.txt", "response3.txt"] 
exp = []

for f in file:
    with open(f, "r") as file:
        content = file.read()
        path = extract_paths(content)
        filtered = filter_successful_paths(path)

        exp += filtered

exp.append('right') # --> it kinda missed this part which was the last value of the maze path

with open("direction.txt", "w") as f:
    for line in exp:
        f.write(line + '\n')

And finally the solve script

import requests
import tqdm
import time

path = []
with open('direction.txt', 'r') as f:
    path = [line.strip() for line in f]

url = 'http://blindmazerevenge.challs.open.ecsc2024.it/maze?direction='
print(path)

with requests.Session() as session:
    response = session.get(url + 'start')
    for value in tqdm.tqdm(path):
        response = session.get(url + value)
        if 'Last Move: FAILED because the maze was busy. Try the move again!' in response.text:
            while 'Last Move: FAILED because the maze was busy. Try the move again!' in response.text:
                response = session.get(url + value)
        time.sleep(0.5)

    print(response.text)

Running the script works and we get the flag image

Flag: openECSC{flag_inside_the_attachment_yes_we_like_it_bb01b0d5}

Anti-rev

image

We are given an executable file and running it to get an overview of what it does shows this image

This seems like we would need to find the expected input inorder to get the right output

Throwing it into a decompiler which in my case IDA gave something like this

Note that’s the decompilation from using dogbolt

IDA didn’t decompile it well and from looking at the control flow graph i saw it had just so many branches

And looking at the disassembly in gdb shows lots of nops & add instruction image image

I suppose this is preventing us from reversing it as the challenge name implies

In order to get around this I first thought of patching the nops & add with a ret but then I remember this can actually be quite the job for angr

So yeah I just grabbed a sample template from here

In our case the win condition is if we get “Correct!” and we would like to avoid any path that would lead to us getting “Wrong!”

Here’s the solve script

Running it gives the flag image

Flag: openECSC{f4nCy_n0p5!_745fb2f2}

WOauth a laundry!

image

We are given a web instance to connect to and on going there shows this image

We can’t view anything as we are not authenticated

Since there’s a login button at the left edge i clicked on it image

It surprisingly worked without even asking for any form of authentication 🤔

We can view the availble laundries or amenities image image

I didn’t see anything of interest here

Checking the session storage shows this image

The value of admin is set to 0 we probably want it to be 1 inorder to view other things?

As of now changing it from the client side won’t really do much at the server side so let’s take a look at the request handling the login

I logged out then relogin while intercepting the request

First it does a GET request to the creds api endpoint image

Intercepting the response to the request shows the client_id & client_secret image

The next request shows this image

This is making a connection via openid which is an interoperable authentication protocol based on the OAuth 2.0 framework src

And looking at the parameters passed as the query I saw this

scope=openid laundry amenities

We can assume that this scope determines what we as an authenticated user would have access to

I appended admin to it since that happens to be a key value in the session storage image

The request seems to work because it was able to generate the access token bearer image

But after doing that I still noticed the admin value in the session is 0 image

Weird.

So i decided to look for endpoint that might be useful

I viewed the page source and saw it’s importing a js file image

./_app/immutable/entry/app.Ck9duSk9.js

I accessed it from the browser but the result looks bad image

We can easily js beautifier it image

Scrolling down the js file shows a new endpoint image

const ae = [() => v(() => import("../nodes/0.DwINNMcl.js"), __vite__mapDeps([0, 1, 2, 3, 4, 5, 6, 7, 8]), import.meta.url), () => v(() => import("../nodes/1.COoiP6uJ.js"), __vite__mapDeps([9, 1, 2, 10, 6]), import.meta.url), () => v(() => import("../nodes/2.CngkQmog.js"), __vite__mapDeps([11, 1, 2, 4, 12, 6, 7]), import.meta.url), () => v(() => import("../nodes/3.D75S8dhM.js"), __vite__mapDeps([13, 1, 2, 3, 4]), import.meta.url), () => v(() => import("../nodes/4.LaKRB8Xm.js"), __vite__mapDeps([14, 1, 2, 12, 4, 15, 5]), import.meta.url), () => v(() => import("../nodes/5.BpDOC5ki.js"), __vite__mapDeps([16, 1, 2, 12, 4, 15, 5]), import.meta.url)],
    le = [],
    fe = {
        "/": [2],
        "/admin": [3],
        "/amenities": [4],
        "/laundry": [5]
    },
    ce = {
        handleError: ({
            error: a
        }) => {
            console.error(a)
        },
        reroute: () => {}
    };
export {
    fe as dictionary, ce as hooks, re as matchers, ae as nodes, oe as root, le as server_loads
};

Let’s try accessing /admin image

It shows a generate button

I confirmed if this is accessible from a normal user and it is but when clicking the button nothing happens image

On the other hand since we have admin as part of the scope it works image

But from the content of what’s generated we would like to maybe change it

Looking at the request that handles the pdf generation shows this image

Unfortunately the body isn’t in the request and we would like to maybe edit it?

I started searching through various js files

And eventually I found a js file that handles the pdf generation

I can’t find it again and i’m lazy to start searching through the whole js files (yes i did this manually 💀)

The body expected was:

{
    "requiredBy": "John Doe"
}

I tried this and it worked image image

At this point we need to exfiltrate the flag

I was familiar with a technique which can be used then all I needed was just to search it up

From searching it I found this

In my case I used the iframe tag

<iframe src=file:///flag.txt></iframe>

Using that works and I got the flag image image

Flag: openECSC{On3_l4uNdrY_70_ruL3_7h3m_4l1!_d208a530}

Thanks for reading!