DownUnderCTF 2024

Abdul Wassay (aka HotPlugin)
7 min readJul 7, 2024

--

1. parrot the emu

It is so nice to hear Parrot the Emu talk back

Solution:

Browsing the challenge URL, we get the following page.

Submit something and it is echoed back

From source code, we find that it’s a flask app and vulnerable to SSTI. It takes user input and passes it into render_template_string which makes it vulnerable.

We can confirm this by using classic SSTI payload {{7*7}}

Now, we can read flag by exploiting SSTI using following payload

{{ self.__init__.__globals__.__builtins__.__import__('os').popen('cat flag').read() }}

2. zoo feedback form

The zoo wants your feedback! Simply fill in the form, and send away, we’ll handle it from there!

Solution

Visiting the URL, we the following feedback form.

Whatever we enter, it is reflected back to us

Looking at the source code, it’s a flask application and it seems to be vulnerable to XXE Injection. It parses the XML request and resolves the entities, which makes it vulnerable.

We can exploit XXE using the following payload

The flags location can be found in the Docker file. We can read it using following payload.

3. co2

A group of students who don’t like to do things the “conventional” way decided to come up with a CyberSecurity Blog post. You’ve been hired to perform an in-depth whitebox test on their web application.

Solution:

Browsing the URL, we get the following page. We can regsiter account.

After registering and logging in, we have a feedback form.

Feedback submission request is sent to /save_feedback endpoint.

Let’s analyze the source code. It’s a flask application. Only focusing on the relevant code, there’s a Feedback class with some attributes. There’s also a flag variable which stores boolean value False.

At the end of file, there’s a /get_flag endpoint which checks if the value of flag variable is true (string) then returns the flag else returns nope. The other interesting endpoint is /save_feedback which taks the user submitted parameters, creates an object of Feeback class and and passes both to the merge function.

The merge function basically takes the user submitted data and recursively sets the properties / attributes of the Feedback class from it. This function is vulnerable to Prototype pollution because it is dynamically setting attributes of Feedback class. You can read more about it here.

We exploit this vulnerability to set the value of global variable flag to “true” using the following payload.

{"title":"test","content":"test","rating":"123","referred":"test",
"__class__":{"__init__":{"__globals__":{"flag":"true"}}}}

Now, sending request to /get_flag endpoint, we get the flag.

4. hah got em

Deez nutz

Hah got em

Oh by the way I love using my new microservice parsing these arrest reports to PDF

Solution:

Browsing the challenge URL, we get a 404 response

Checking the provided source code, we have only a Docker file which tells that it’s gotenberg v8.0.3 and the location of flag is /etc/flag.txt

Gotenberg provides a developer-friendly API to interact with powerful tools like Chromium and LibreOffice for converting numerous document formats (HTML, Markdown, Word, Excel, etc.) into PDF files, and more!

Searching for CVEs, I coundn’t find anything relevant. Looking at it’s documentation, it accepts URL, MD and HTML and converts them to PDF. So, first thing comes to mind is SSRF. But it does not work.

# via URL
curl --request POST https://web-hah-got-em-20ac16c4b909.2024.ductf.dev/forms/chromium/convert/url --form url=/etc/flag.txt -o a.pdf

# via HTML
curl --request POST https://web-hah-got-em-20ac16c4b909.2024.ductf.dev/forms/chromium/convert/html --form files=@index.html -o my.pdf -k

Next i went to Github releases of Gotenberg. After version 8.0.3, the new version is 8.1.0 which has a security update of a file read vulnerability.

I went to diff both versions to find what was fixed :D

There seems to be a change in Regex deny list

Going further down, if found two test cases which seems to be testing the file read vulnerability that was mentioned in the update.

Trying these, we get success with the second one

Now we can read the flag using following.

5. i am confusion

The evil hex bug has taken over our administrative interface of our application. It seems that the secret we used to protect our authentication was very easy to guess. We need to get it back!

Solution:

Browsing the challenge URL, we get the following login page

Entering any credentials, we get logged in.

Clicking on Switch to Admin gives following page :D

Analyzing the source code, it seems to be using JWT. At the very start, we can see that it is defining one asymmetric algorithm for signing the JWT which is RS256. And two algorithms for verifying the JWT (HS256 Symmetric & RS256 Asymmetric). Here, we can assume that it’s gonna be algorithm confusion attack.

Looking at the /login endpoint, it checks if the username is admin then returns error otherwise it signs a JWT using the RS256 algorithm which is Asymmetric.

The /admin endpoint contains the flag. However to access this, we need a JWT with admin username. Here, we can see that it uses two algorithms, both HS256 (symmetric) and RS256 (Asymmetric) to verify the JWT. This verification is vulnerable to Algorithm Confusion attack because if we provide a JWT token signed using a symmetric algorithm like HS256, the library’s generic verify() method will treat the public key as an HMAC secret. This means that an we can sign the token using HS256 and the public key, and the server will use the same public key to verify the signature. As the name suggests the public key is public and can be extracted from JWT :D

To extract the public key, we use jwt_forgery tool from portswigger. We need to provide two JWTs to the tool. Here’s the command to run it in a docker. This tool outputs aBase64-encoded PEM key in both X.509 and PKCS1 format and forged JWT signed using each of these keys.

docker run --rm -it portswigger/sig2n <token1> <token2>

Next, to find which one is correct public key, replace the use the Tampered JWT from the above output on the /profile endpoint. For me, the last one worked like a charm.

Now copy the Base64 encoded PKCS1 key above of tampered JWT from the tool output and go to jwt.io. Here’s first paste the untampered JWT token, then change the algorithm to HS256. At bottom select the base64 encoded secret and paste the PKCS1 key. Finally change the username to admin.

Use this forged JWT to access the /admin.html page and get the flag.

--

--

Abdul Wassay (aka HotPlugin)
Abdul Wassay (aka HotPlugin)

No responses yet