Some IngeHack CTF 2021 writeups

This last weekend my team Heaven’s_Birds participated in IngeHack national CTF organized by Ingeniums club from the higher national school of computer science sidi bel abbes and got 2nd place.

These are some of the challenges that I solved and really enjoyed and learned from them :

Smokkelen :

The first challenge is “Smokkelen” in the web category, where we were given a chatting web application that uses flask as a backend, and Vanish as a reverse proxy and communicates through WebSockets.

We had a backend that exposes public WebSocket API and also has an internal REST API not available from outside. what we needed to do is to access the internal REST API and read the flag at localhost:5000/flag.txt.

Thanks to the 3 months time I took to learn german, the challenge name seemed to me like a german word so I translated it to smuggle in English, and at this point, it was obvious to me that I’m dealing with a request smuggling attack through WebSockets and I googled it and found this GitHub link to exactly how to perform this attack “https://github.com/0ang3el/websocket-smuggle”.

What was needed to do is to first send an upgrade request to reverse proxy but with the wrong protocol version inside the header Sec-WebSocket-Version (different than 13), the proxy doesn’t validate the header and translates the request to the backend, then the backend sends a response with status code 426 because protocol version is incorrect inside the header Sec-WebSocket-Version. However, a reverse proxy doesn't check enough response from the backend (including status code) and thinks that the backend is ready for WebSocket communication. Further, it translates the request to the client, Finally, reverse proxy thinks that a WebSocket connection is established between client and backend. In reality, there is no WebSocket connection (the backend refused the Upgrade request). At the same time, proxy keeps TCP or TLS connection between client and backend in an open state.

POC :

flag : IngeHack{d03s_v4rn1sh_s3cur3_w3bs0ck3t_c0nn3ct10ns?}

Jongoo 1 :

In this challenge, we were given a Django web application where we can list available posts, search posts, insert comments

As you may notice in the team's navBar, team7’s name is written team{{7*1}} which is a straightforward hint that we are dealing with a server-side template injection “ssti”, all that’s left is to find the point of injection, id we try to filter posts we see that our filter is being reflected :

the view for this endpoint is below :

I kept trying usual injections but kept getting server error, so I started looking for objects used in other template files and found the object{{request}}

I wanted to access its attributes so I set a breakpoint in the view and found the attribute ‘environ’, and bingo :

flag : IngeHack{3v3n_Djang0_d03snt_surv1v3_sst1}

Jongoo 2 :

This challenge is the continuation of the preview challenge, we were asked to get RCE and if you may be noticed in the previews challenge we also got the secret key for the Django app.

After spending some time googling for ways to exploit the secret key, I found out that this app is using cookie-based sessions with personalized PickleSerializer

let’s view the serializer :

At this point our game was obvious, all we need is to serialize our payload sign it using the secret key we have, and make a request with our forged cookie to execute our code, the only thing we need to do is to see what’s happening when deserializing our object.

By default, unpickling will import any class or function that it finds in the pickle data but unfortunately for us, our custom find_class() only allows the builtins module to be used, so we only need to use functions from this module which includes eval, exec …

Now to the fun part, building our exploit :

first, we import the used serializer, builtins module, Django cookie signing module, and create our payload which is a base64 encoded python3 reverse shell and then we create our lass to generate our pickle object with our payload inside it and finally we use the Django signing dumps function to generate our signed cookie, making a request with the forged cookie gives us a reverse connection and we can simply cat out flag.txt.

flag : IngeHack{g0000000000d_h3r3_1s_y0ur_fl4g_https://docs.djangoproject.com/fr/3.2/topics/http/sessions/#using-cookie-based-sessions}

hey :)