CTFZone Paper: Trust Area — Backend Part

By Arkadiy Litvinenko

Part II: CTFZone Paper: Trust Area — Client Part
Part III: CTFZone Paper: Trust Area — Infra

Introduction

We had long aspired to create a task for attack-defense CTF competitions involving the detection and exploitation of vulnerabilities in Android-powered mobile applications. However, we had many doubts concerning the task architecture, since we lacked an understanding of how it was supposed to work. It was only recently — during the preparation for CTFZone Finals 2020 — that we finally decided to implement this idea. In this article, we compile the technical details of what we ended up with :)

Task architecture

Every team that had made it to the attack-defense stage was provided with its own backend hosted on its dedicated game server. The players were granted full access to the server. The teams could not communicate with the backends of other participants directly, which was restricted on the network level. Also, every team had a mobile application deployed on an Android emulator in the task infrastructure. The Android apps could communicate with the other teams’ backends through HTTP and with other applications in the emulator — using the IPC (inter-process communication) mechanisms. The teams had sources of APKs and could modify them. Every round, the emulator extracted a new APK version from the special folder on the team’s backend and deployed it. The backend and APKs contained vulnerabilities that could be exploited by the players for capturing flags. There was also a checker installed on the emulator, which communicated with the teams’ APKs and backends. We will dig deeper into the checker’s functions and APKs in parts 2 and 3 of this article.

Fig. 1 below presents a sketch of the task infrastructure (based on the architecture solution) from the README task. The players could study it before starting the task:

Let us focus on each infrastructure component in more detail.

Backend

Architecture

We went with Golang as the primary language and used Docker Compose for deployment. Given that the task itself had some novelties, we decided to avoid any ‘exotic’ backend solutions. As a result, we created a typical web application with PostgreSQL and Redis as session storage.

Applying Docker Compose in a CTF task gave two significant advantages:

  1. Every player could quickly deploy the task and test it locally.
  2. 2. We, as organisers, could select any bunch of services for the task, having the freedom to add any vulnerabilities and exploitation chains.

Vulnerability complexity dilemma

One of the dilemmas was to determine how complex the backend vulnerabilities should be — in terms of detection, mitigation and exploitation. To do this, we had to take into account the specifics of the task and time limitations. Within the allocated time, the participants had to gain an understanding of how this new task worked, find the vulnerabilities, and (the hardest part) add code to their mobile application to exploit these vulnerabilities.

The vulnerabilities were not supposed to be too complex; otherwise, we were running the risk of no one being able to solve the task. Likewise, they were not supposed to be too simple, as the teams would have fixed them in less than no time.

Given the above, we ended up rolling out six simple/medium vulnerabilities, scattered across the backend — not only in Golang.

In theory, there was meant to be plenty of time for exploitation and other activities. In practice, though, several teams proved quicker than expected at spotting the vulnerabilities, while others focused a lot of time on trying to identify and patch the bugs. This allowed the attackers to collect flags and interfere with each other :)

Description of vulnerabilities

1. IDOR

Before describing the IDOR vulnerability, let us provide a brief overview of the main backend logic. Users were allowed to create tasks with a challenge and a reward based on solving this challenge. A challenge represented a string with a SHA1 hash of another random string. The players could receive a reward only after submitting the correct string whose SHA1 hash equalled the challenge string. As the random strings were massive, it was impossible to get them by fair means.

However, we created an IDOR vulnerability, which allowed a player to overwrite the challenge of another player’s task. It enabled an attacker to solve any task quickly and win the reward. Besides, this vulnerability brought the service down — when the checker returned to check the task it had created, the solution was already incorrect.

2. Nginx misconfiguration

Nginx had a vulnerability related to the unsafe use of the alias. Nginx configuration snippet:

As evident from the snippet, the attacker could conduct a path traversal attack and read the files from the upper directory, including logs with flags.

Check out this link for more information about this type of vulnerability.

3. and 4. SQL injections

The backend contained two classical SQL injection vulnerabilities in different locations:

and

These are typical SQL injections, but for one exception: in the second instance, you have to use $escape$ instead of ' :)

5. Open Redis port

Docker Compose had two configurations: dev and prod. By default, the service used the prod configuration, which contained only one vulnerability — a forwarded Redis port:

The teams thereby could gain information about user sessions from Redis and extract flags with the help of this data. Potentially, the players could have used a master-slave in Redis to get RCE, but de facto it was useless due to a separate Docker container.

6. Refresh token leakage

The authentication mechanism of our mobile application relied on refresh and access tokens. Generally, refresh tokens carry the information necessary to get a new access token, which serves to make authenticated calls to a secured API. In our case, a refresh token represented the user’s UUID (Universally Unique Identifier). Thus, knowing the UUID, a threat actor could generate an access token and gain access to the user’s information. The code snippet below was used to extract UUIDs by usernames:

Source code:

International community conference for cybersecurity researchers and professionals. No suits, no business — only hardcore research.