Пример #1
0
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)
Пример #2
0
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')
Пример #3
0
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)
Пример #4
0
    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')
Пример #5
0
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'))
Пример #6
0
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())
Пример #7
0
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')
Пример #8
0
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)
Пример #9
0
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'))
Пример #10
0
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')})
Пример #11
0
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')