def confirm_user(data=None): if not utils.get_config('verify_emails'): # If the CTF doesn't care about confirming email addresses then redierct to challenges return redirect(url_for('challenges.challenges_view')) logger = logging.getLogger('regs') # User is confirming email account if data and request.method == "GET": try: s = TimedSerializer(app.config['SECRET_KEY']) email = s.loads(utils.base64decode(data, urldecode=True), max_age=1800) except BadTimeSignature: return render_template('confirm.html', errors=[get_tip('LINK_EXPIRED')]) except (BadSignature, TypeError, base64.binascii.Error): return render_template('confirm.html', errors=[get_tip('INVIDE_RESET_TOKEN')]) team = Teams.query.filter_by(email=email).first_or_404() team.verified = True db.session.commit() logger.warn( get_tip('USER_HAVE_CM').format(date=time.strftime("%m/%d/%Y %X"), ip=utils.get_ip(), username=team.name.encode('utf-8'), email=team.email.encode('utf-8'))) db.session.close() if utils.authed(): return redirect(url_for('challenges.challenges_view')) return redirect(url_for('auth.login')) # User is trying to start or restart the confirmation flow if not utils.authed(): return redirect(url_for('auth.login')) team = Teams.query.filter_by(id=session['id']).first_or_404() if data is None: if request.method == "POST": # User wants to resend their confirmation email if team.verified: return redirect(url_for('views.profile')) else: utils.verify_email(team.email) logger.warn( get_tip('EMAIL_CF_RESENT').format( date=time.strftime("%m/%d/%Y %X"), ip=utils.get_ip(), username=team.name.encode('utf-8'), email=team.email.encode('utf-8'))) return render_template('confirm.html', team=team, infos=[get_tip('EMAIL_CF_SENT')]) elif request.method == "GET": # User has been directed to the confirm page team = Teams.query.filter_by(id=session['id']).first_or_404() if team.verified: # If user is already verified, redirect to their profile return redirect(url_for('views.profile')) return render_template('confirm.html', team=team)
def login(): logger = logging.getLogger('logins') if request.method == 'POST': errors = [] name = request.form['name'] # Check if the user submitted an email address or a team name if utils.check_email_format(name) is True: team = Teams.query.filter_by(email=name).first() else: team = Teams.query.filter_by(name=name).first() if team: if team and bcrypt_sha256.verify(request.form['password'], team.password): try: session.regenerate() # NO SESSION FIXATION FOR YOU except: pass # TODO: Some session objects don't implement regenerate :( session['username'] = team.name session['id'] = team.id session['admin'] = team.admin session['nonce'] = utils.sha512(os.urandom(10)) db.session.close() logger.warn( get_tip('USER_LOGINED').format( date=time.strftime("%m/%d/%Y %X"), ip=utils.get_ip(), username=session['username'].encode('utf-8'))) if request.args.get('next') and utils.is_safe_url( request.args.get('next')): return redirect(request.args.get('next')) return redirect(url_for('challenges.challenges_view')) else: # This user exists but the password is wrong logger.warn( get_tip('INVIDE_PASS').format( date=time.strftime("%m/%d/%Y %X"), ip=utils.get_ip(), username=team.name.encode('utf-8'))) errors.append(get_tip('INVIDE_USER_PASS')) db.session.close() return render_template('login.html', errors=errors) else: # This user just doesn't exist logger.warn( get_tip('INVIDE_USER').format( date=time.strftime("%m/%d/%Y %X"), ip=utils.get_ip())) errors.append(get_tip('INVIDE_USER_PASS')) db.session.close() return render_template('login.html', errors=errors) else: db.session.close() return render_template('login.html')
def hints_view(hintid): if utils.ctf_started() is False: if utils.is_admin() is False: abort(403) hint = Hints.query.filter_by(id=hintid).first_or_404() chal = Challenges.query.filter_by(id=hint.chal).first() unlock = Unlocks.query.filter_by(model='hints', itemid=hintid, teamid=session['id']).first() if request.method == 'GET': if unlock: return jsonify({ 'hint': hint.hint, 'chal': hint.chal, 'cost': hint.cost }) else: return jsonify({'chal': hint.chal, 'cost': hint.cost}) elif request.method == 'POST': if unlock is None: # The user does not have an unlock. if utils.ctftime() or ( utils.ctf_ended() and utils.view_after_ctf()) or utils.is_admin() is True: # It's ctftime or the CTF has ended (but we allow views after) team = Teams.query.filter_by(id=session['id']).first() if team.score() < hint.cost: return jsonify({'errors': get_tip('NOT_ENOUGH_POINT')}) unlock = Unlocks(model='hints', teamid=session['id'], itemid=hint.id) award = Awards(teamid=session['id'], name=text_type( get_tip('HIT_FOR').format(chal.name)), value=(-hint.cost)) db.session.add(unlock) db.session.add(award) db.session.commit() json_data = { 'hint': hint.hint, 'chal': hint.chal, 'cost': hint.cost } db.session.close() return jsonify(json_data) elif utils.ctf_ended(): # The CTF has ended. No views after. abort(403) else: # The user does have an unlock, we should give them their hint. json_data = { 'hint': hint.hint, 'chal': hint.chal, 'cost': hint.cost } db.session.close() return jsonify(json_data)
def attempt(chal, request): """ This method is used to check whether a given input is right or wrong. It does not make any changes and should return a boolean for correctness and a string to be shown to the user. It is also in charge of parsing the user's input from the request itself. :param chal: The Challenge object from the database :param request: The request the user submitted :return: (boolean, string) """ provided_key = request.form['key'].strip() chal_keys = Keys.query.filter_by(chal=chal.id).all() for chal_key in chal_keys: if get_key_class(chal_key.type).compare(chal_key.flag, provided_key): return True, utils.get_tip('T_CORRECT') return False, utils.get_tip('T_INCORRECT')
def challenges_view(): infos = [] errors = [] start = utils.get_config('start') or 0 end = utils.get_config('end') or 0 if utils.ctf_paused(): infos.append(get_tip('IS_PAUSED').format(utils.ctf_name())) if not utils.is_admin(): # User is not an admin if not utils.ctftime(): # It is not CTF time if utils.view_after_ctf( ): # But we are allowed to view after the CTF ends pass else: # We are NOT allowed to view after the CTF ends if utils.get_config('start') and not utils.ctf_started(): errors.append( get_tip('NOT_START').format(utils.ctf_name())) if (utils.get_config('end') and utils.ctf_ended()) and not utils.view_after_ctf(): errors.append(get_tip('HAS_END').format(utils.ctf_name())) return render_template('challenges.html', infos=infos, errors=errors, start=int(start), end=int(end)) if utils.get_config('verify_emails'): if utils.authed(): if utils.is_admin() is False and utils.is_verified( ) is False: # User is not confirmed return redirect(url_for('auth.confirm_user')) if utils.user_can_view_challenges(): # Do we allow unauthenticated users? if utils.get_config('start') and not utils.ctf_started(): errors.append(get_tip('NOT_START').format(utils.ctf_name())) if (utils.get_config('end') and utils.ctf_ended()) and not utils.view_after_ctf(): errors.append(get_tip('HAS_END').format(utils.ctf_name())) return render_template('challenges.html', infos=infos, errors=errors, start=int(start), end=int(end)) else: return redirect(url_for('auth.login', next='challenges'))
def scoreboard_view(): if utils.get_config('view_scoreboard_if_authed') and not utils.authed(): return redirect(url_for('auth.login', next=request.path)) if utils.hide_scores(): return render_template('scoreboard.html', errors=[utils.get_tip('SCORE_HIDDEN')]) standings = get_standings() return render_template('scoreboard.html', teams=standings, score_frozen=utils.is_scoreboard_frozen())
def reset_password(data=None): logger = logging.getLogger('logins') if data is not None: try: s = TimedSerializer(app.config['SECRET_KEY']) name = s.loads(utils.base64decode(data, urldecode=True), max_age=1800) except BadTimeSignature: return render_template('reset_password.html', errors=[get_tip('LINK_EXPIRED')]) except (BadSignature, TypeError, base64.binascii.Error): return render_template('reset_password.html', errors=[get_tip('INVIDE_RESET_TOKEN')]) if request.method == "GET": return render_template('reset_password.html', mode='set') if request.method == "POST": team = Teams.query.filter_by(name=name).first_or_404() team.password = bcrypt_sha256.encrypt( request.form['password'].strip()) db.session.commit() logger.warn( get_tip('PASS_HAVE_RESET').format( date=time.strftime("%m/%d/%Y %X"), ip=utils.get_ip(), username=team.name.encode('utf-8'))) db.session.close() return redirect(url_for('auth.login')) if request.method == 'POST': email = request.form['email'].strip() team = Teams.query.filter_by(email=email).first() errors = [] if utils.can_send_mail() is False: return render_template('reset_password.html', errors=[get_tip('EMAIL_NOT_CONFIG')]) if not team: return render_template('reset_password.html', errors=[get_tip('FORGOT_PASS_NOTICE')]) utils.forgot_password(email, team.name) return render_template('reset_password.html', errors=[get_tip('FORGOT_PASS_NOTICE')]) return render_template('reset_password.html')
def team(teamid): if utils.get_config('workshop_mode'): abort(404) if utils.get_config('view_scoreboard_if_utils.authed') and not utils.authed(): return redirect(url_for('auth.login', next=request.path)) errors = [] freeze = utils.get_config('freeze') user = Teams.query.filter_by(id=teamid).first_or_404() solves = Solves.query.filter_by(teamid=teamid) awards = Awards.query.filter_by(teamid=teamid) place = user.place() score = user.score() if freeze: freeze = utils.unix_time_to_utc(freeze) if teamid != session.get('id'): solves = solves.filter(Solves.date < freeze) awards = awards.filter(Awards.date < freeze) solves = solves.all() awards = awards.all() db.session.close() if utils.hide_scores() and teamid != session.get('id'): errors.append(get_tip('SCORE_HIDDEN')) if errors: return render_template('team.html', team=user, errors=errors) if request.method == 'GET': return render_template('team.html', solves=solves, awards=awards, team=user, score=score, place=place, score_frozen=utils.is_scoreboard_frozen()) elif request.method == 'POST': json = {'solves': []} for x in solves: json['solves'].append({'id': x.id, 'chal': x.chalid, 'team': x.teamid}) return jsonify(json)
def profile(): if utils.authed(): if request.method == "POST": errors = [] name = request.form.get('name').strip() email = request.form.get('email').strip() website = request.form.get('website').strip() affiliation = request.form.get('affiliation').strip() country = request.form.get('country').strip() member = request.form.get('member').strip() number = request.form.get('number').strip() print member,number user = Teams.query.filter_by(id=session['id']).first() if not utils.get_config('prevent_name_change'): names = Teams.query.filter_by(name=name).first() name_len = len(request.form['name']) == 0 emails = Teams.query.filter_by(email=email).first() valid_email = utils.check_email_format(email) if utils.check_email_format(name) is True: errors.append(get_tip('EMAIL_NOT_TEAM')) if ('password' in request.form.keys() and not len(request.form['password']) == 0) and \ (not bcrypt_sha256.verify(request.form.get('confirm').strip(), user.password)): errors.append(get_tip('PASS_NOT_MATCH')) if not valid_email: errors.append(get_tip('INVIDE_EMAIL')) if not utils.get_config('prevent_name_change') and names and name != session['username']: errors.append(get_tip('TEAM_EXIST')) if emails and emails.id != session['id']: errors.append(get_tip('EMAIL_HAVE_USE')) if not utils.get_config('prevent_name_change') and name_len: errors.append(get_tip('TOO_SHORT_TEAM')) if website.strip() and not utils.validate_url(website): errors.append(get_tip('INVIDE_LINK_FORMAT')) if len(errors) > 0: return render_template('profile.html', name=name, email=email, website=website, affiliation=affiliation, country=country,member=member, number=number, errors=errors) else: team = Teams.query.filter_by(id=session['id']).first() if team.name != name: if not utils.get_config('prevent_name_change'): team.name = name session['username'] = team.name if team.email != email.lower(): team.email = email.lower() if utils.get_config('verify_emails'): team.verified = False if 'password' in request.form.keys() and not len(request.form['password']) == 0: team.password = bcrypt_sha256.encrypt(request.form.get('password')) team.website = website team.affiliation = affiliation '''member info need lock ''' if not utils.get_config('prevent_name_change'): team.country = country team.member = member team.number = number db.session.commit() db.session.close() return redirect(url_for('views.profile')) else: user = Teams.query.filter_by(id=session['id']).first() name = user.name email = user.email website = user.website affiliation = user.affiliation country = user.country member = user.member number = user.number prevent_name_change = utils.get_config('prevent_name_change') confirm_email = utils.get_config('verify_emails') and not user.verified return render_template('profile.html', name=name, email=email, website=website, affiliation=affiliation, country=country,member=member,number=number, prevent_name_change=prevent_name_change, confirm_email=confirm_email) else: return redirect(url_for('auth.login'))
def chal(chalid): if utils.ctf_paused(): return jsonify({ 'status': 3, 'message': get_tip('IS_PAUSED').format(utils.ctf_name()) }) if utils.ctf_ended() and not utils.view_after_ctf(): abort(403) if not utils.user_can_view_challenges(): return redirect(url_for('auth.login', next=request.path)) if (utils.authed() and utils.is_verified() and (utils.ctf_started() or utils.view_after_ctf())) or utils.is_admin(): team = Teams.query.filter_by(id=session['id']).first() fails = WrongKeys.query.filter_by(teamid=session['id'], chalid=chalid).count() logger = logging.getLogger('keys') data = (time.strftime("%m/%d/%Y %X"), session['username'].encode('utf-8'), request.form['key'].encode('utf-8'), utils.get_kpm(session['id'])) print("[{0}] {1} submitted {2} with kpm {3}".format(*data)) chal = Challenges.query.filter_by(id=chalid).first_or_404() if chal.hidden: abort(404) chal_class = get_chal_class(chal.type) # Anti-bruteforce / submitting keys too quickly if utils.get_kpm(session['id']) > 10: if utils.ctftime(): chal_class.fail(team=team, chal=chal, request=request) logger.warn( "[{0}] {1} submitted {2} with kpm {3} [TOO FAST]".format( *data)) # return '3' # Submitting too fast return jsonify({ 'status': 3, 'message': get_tip('SUBMIT_TOO_FAST') }) solves = Solves.query.filter_by(teamid=session['id'], chalid=chalid).first() # Challange not solved yet if not solves: provided_key = request.form['key'].strip() saved_keys = Keys.query.filter_by(chal=chal.id).all() # Hit max attempts max_tries = chal.max_attempts if max_tries and fails >= max_tries > 0: return jsonify({ 'status': 0, 'message': get_tip('ZERO_CAN_TRY') }) status, message = chal_class.attempt(chal, request) if status: # The challenge plugin says the input is right if utils.ctftime() or utils.is_admin(): chal_class.solve(team=team, chal=chal, request=request) logger.info( "[{0}] {1} submitted {2} with kpm {3} [CORRECT]".format( *data)) return jsonify({'status': 1, 'message': message}) else: # The challenge plugin says the input is wrong if utils.ctftime() or utils.is_admin(): chal_class.fail(team=team, chal=chal, request=request) logger.info( "[{0}] {1} submitted {2} with kpm {3} [WRONG]".format( *data)) # return '0' # key was wrong if max_tries: attempts_left = max_tries - fails - 1 # Off by one since fails has changed since it was gotten tries_str = 'tries' if attempts_left == 1: tries_str = 'try' if message[ -1] not in '!().;?[]\{\}': # Add a punctuation mark if there isn't one message = message + '.' return jsonify({ 'status': 0, 'message': get_tip('MANY_CAN_TRY').format(message, attempts_left, tries_str) }) else: return jsonify({'status': 0, 'message': message}) # Challenge already solved else: logger.info( "{0} submitted {1} with kpm {2} [ALREADY SOLVED]".format( *data)) # return '2' # challenge was already solved return jsonify({'status': 2, 'message': get_tip('HAVE_SOLVE')}) else: return jsonify({'status': -1, 'message': get_tip('MUST_LOGGED')})
def register(): logger = logging.getLogger('regs') if not utils.can_register(): return redirect(url_for('auth.login')) if request.method == 'POST': errors = [] name = request.form['name'] email = request.form['email'] password = request.form['password'] name_len = len(name) == 0 names = Teams.query.add_columns('name', 'id').filter_by(name=name).first() emails = Teams.query.add_columns('email', 'id').filter_by(email=email).first() pass_short = len(password) == 0 pass_long = len(password) > 128 valid_email = utils.check_email_format(request.form['email']) team_name_email_check = utils.check_email_format(name) if not valid_email: errors.append(get_tip('INVIDE_EMAIL')) if names: errors.append(get_tip('TEAM_EXIST')) if team_name_email_check is True: errors.append(get_tip('EMAIL_NOT_TEAM')) if emails: errors.append(get_tip('EMAIL_HAVE_USE')) if pass_short: errors.append(get_tip('TOO_SHORT_PASS')) if pass_long: errors.append(get_tip('TOO_LONG_PASS')) if name_len: errors.append(get_tip('TOO_SHORT_TEAM')) if len(errors) > 0: return render_template('register.html', errors=errors, name=request.form['name'], email=request.form['email'], password=request.form['password']) else: with app.app_context(): token = os.urandom(16).encode('hex') team = Teams(name, email.lower(), password, token.lower()) db.session.add(team) db.session.commit() db.session.flush() session['username'] = team.name session['id'] = team.id session['admin'] = team.admin session['nonce'] = utils.sha512(os.urandom(10)) if utils.can_send_mail() and utils.get_config( 'verify_emails' ): # Confirming users is enabled and we can send email. logger = logging.getLogger('regs') logger.warn( get_tip('USER_REG_WARN').format( date=time.strftime("%m/%d/%Y %X"), ip=utils.get_ip(), username=request.form['name'].encode('utf-8'), email=request.form['email'].encode('utf-8'))) utils.verify_email(team.email) db.session.close() return redirect(url_for('auth.confirm_user')) else: # Don't care about confirming users if utils.can_send_mail( ): # We want to notify the user that they have registered. utils.sendmail( request.form['email'], get_tip('USER_REG_SUCCESS').format( utils.get_config('ctf_name'))) logger.warn( get_tip('USER_REGISTRED').format( date=time.strftime("%m/%d/%Y %X"), ip=utils.get_ip(), username=request.form['name'].encode('utf-8'), email=request.form['email'].encode('utf-8'))) db.session.close() return redirect(url_for('challenges.challenges_view')) else: return render_template('register.html')