Beispiel #1
0
def test_register_plugin_stylesheet():
    '''Test that register_plugin_stylesheet adds stylesheet paths to the core theme when used from a plugin'''
    app = create_ctfd()
    with app.app_context():
        register_plugin_script('/fake/stylesheet/path.css')
        register_plugin_script('http://ctfd.io/fake/stylesheet/path.css')
        with app.test_client() as client:
            r = client.get('/')
            output = r.get_data(as_text=True)
            assert '/fake/stylesheet/path.css' in output
            assert 'http://ctfd.io/fake/stylesheet/path.css' in output
    destroy_ctfd(app)
def test_register_plugin_script():
    """Test that register_plugin_script adds script paths to the core theme when used from a plugin"""
    app = create_ctfd()
    with app.app_context():
        register_plugin_script("/fake/script/path.js")
        register_plugin_script("http://ctfd.io/fake/script/path.js")
        with app.test_client() as client:
            r = client.get("/")
            output = r.get_data(as_text=True)
            assert "/fake/script/path.js" in output
            assert "http://ctfd.io/fake/script/path.js" in output
    destroy_ctfd(app)
Beispiel #3
0
def test_register_plugin_stylesheet():
    """Test that register_plugin_stylesheet adds stylesheet paths to the core theme"""
    app = create_ctfd()
    with app.app_context():
        register_plugin_script("/fake/stylesheet/path.css")
        register_plugin_script(
            "http://examplectf.com/fake/stylesheet/path.css")
        with app.test_client() as client:
            r = client.get("/")
            output = r.get_data(as_text=True)
            assert "/fake/stylesheet/path.css" in output
            assert "http://examplectf.com/fake/stylesheet/path.css" in output
    destroy_ctfd(app)
def load(app):
    # upgrade()
    app.db.create_all()
    CHALLENGE_CLASSES['lah'] = LahChallengeClass
    register_plugin_assets_directory(app, base_path='/plugins/lah_challenges/assets/')
    global APP_REF
    APP_REF = app
    scheduler.start()
    atexit.register(lambda: scheduler.shutdown())

    app.register_blueprint(lah_print)
    register_user_page_menu_bar("Unlocking", "/unlock")
    register_plugin_script("/plugins/lah_challenges/assets/lah_challenge_injector.js")
Beispiel #5
0
def load(app):
    app.db.create_all()
    app.register_blueprint(assets)

    dir_path = os.path.dirname(os.path.realpath(__file__))
    template_path = os.path.join(dir_path, 'templates/settings_new.html')
    override_template('settings.html', open(template_path).read())

    register_plugin_assets_directory(
        app, base_path='/plugins/ctfd-plugin-openvpn/assets/')
    register_plugin_script(
        '/plugins/ctfd-plugin-openvpn/assets/settings_new.js')

    print("OpenVPN-Cfg plugin is ready!")
Beispiel #6
0
def load(app):
    def wrap_method(name, wrapper):
        old = app.view_functions[name]
        app.view_functions[name] = wrapper(old)

    app.db.create_all()

    # override code which renders challenges to show when future challenges will be released.
    app.view_functions["challenges.chals"] = get_available_challenges

    # override method which render's challenge's data
    wrap_method("challenges.chal_view", satisfies_challenge_timed_releases)

    # disallow attempts to solve future challenges
    wrap_method("challenges.chal", satisfies_challenge_timed_releases)

    app.register_blueprint(plugin_blueprint)
    register_plugin_assets_directory(app, base_path='/plugins/ctfd-timed-releases-plugin/src/assets/')
    register_plugin_script('/plugins/ctfd-timed-releases-plugin/src/assets/countdown.js')
Beispiel #7
0
def load(app):
    notify = Blueprint('notify', __name__, template_folder='templates')
    notify_static = Blueprint('notify_static', __name__, static_folder='static')

    @notify.route('/admin/plugins/notify/send', methods=['GET', 'POST'])
    @admins_only
    def notify_send():
        if request.method == 'GET':
            return render_template('notify.html')
        elif request.method == 'POST':
            msg = request.form.get('msg')
            title = request.form.get('title')
            client_secret = get_config('thunderpush_client_secret')
            server_secret = get_config('thunderpush_server_secret')
            thunderpush_url = get_config('thunderpush_url')
            thunderpush_port = get_config('thunderpush_port')
            t = Thunder(apikey=client_secret, apisecret=server_secret, host=thunderpush_url, port=thunderpush_port)
            t.send_message_to_channel(channel='all_teams', message={'title': title, 'msg': msg})
            return '', 200

    @notify.route('/notify/static/ctfd-notify.js', methods=['GET'])
    def notify_static_generator():
        client_secret = get_config('thunderpush_client_secret')
        thunderpush_url = get_config('thunderpush_url')
        thunderpush_port = get_config('thunderpush_port')
        js = render_template('ctfd-notify.js', url=thunderpush_url, port=thunderpush_port, secret=client_secret)
        return Response(js, mimetype='application/javascript')

    app.register_blueprint(notify)
    app.register_blueprint(notify_static, url_prefix='/notify')
    scripts = [
        "/notify/static/sockjs-0.3.4.min.js",
        "/notify/static/thunderpush.js",
        "/notify/static/push.min.js",
        "/notify/static/ctfd-notify.js"
    ]
    for s in scripts:
        register_plugin_script(s)
Beispiel #8
0
def load(app):
    # set_index_content()
    # import_users()
    register_plugin_assets_directory(app,
                                     base_path='/plugins/flaganizer/assets/')
    register_plugin_script('/plugins/flaganizer/assets/flaganizer.js')

    @app.route('/flaganizer-submit', methods=['POST'])
    def flaganizer_submit():
        if authed() is False:
            return {
                "success": True,
                "data": {
                    "status": "authentication_required"
                }
            }, 403

        if request.content_type != "application/json":
            request_data = request.form
        else:
            request_data = request.get_json()

        if ctf_paused():
            return (
                {
                    "success": True,
                    "data": {
                        "status": "paused",
                        "message": "{} is paused".format(config.ctf_name()),
                    },
                },
                403,
            )

        user = get_current_user()
        team = get_current_team()

        # TODO: Convert this into a re-useable decorator
        if config.is_teams_mode() and team is None:
            abort(403)

        kpm = current_user.get_wrong_submissions_per_minute(user.account_id)

        frsp = requests.post(FLAGANIZER_VERIFY_ENDPOINT,
                             data={
                                 "flag": request_data.get("submission", "")
                             },
                             headers={
                                 "X-CTFProxy-SubAcc-JWT":
                                 request.headers.get("X-CTFProxy-JWT")
                             }).json()
        if frsp["Success"] == 0:
            if ctftime() or current_user.is_admin():
                placeholder_challenge = Challenges.query.filter_by(
                    name="wrong submission").first()
                if placeholder_challenge is None:
                    placeholder_challenge = Challenges(
                        name="wrong submission",
                        description=FLAGANIZER_DESCRIPTION_PREFIX +
                        "a placeholder challenge for unrecognized flags",
                        value=0,
                        category="misc",
                        state="hidden",
                        max_attempts=0)
                    db.session.add(placeholder_challenge)
                    db.session.commit()
                    db.session.close()
                    placeholder_challenge = Challenges.query.filter_by(
                        name="wrong submission").first()
                chal_class = get_chal_class(placeholder_challenge.type)
                if placeholder_challenge is not None:
                    chal_class.fail(user=user,
                                    team=team,
                                    challenge=placeholder_challenge,
                                    request=request)
                    clear_standings()
            log(
                "submissions",
                "[{date}] {name} submitted {submission} via flaganizer with kpm {kpm} [WRONG]",
                submission=request_data.get("submission", "").encode("utf-8"),
                kpm=kpm,
            )
            return {
                "success": True,
                "data": {
                    "status": "incorrect",
                    "message": frsp["Message"]
                },
            }

        challenge = Challenges.query.filter_by(
            description=FLAGANIZER_DESCRIPTION_PREFIX +
            frsp["Flag"]["Id"]).first()
        if challenge is None:
            challenge = Challenges(name=frsp["Flag"]["DisplayName"],
                                   description=FLAGANIZER_DESCRIPTION_PREFIX +
                                   frsp["Flag"]["Id"],
                                   value=frsp["Flag"]["Points"],
                                   category=frsp["Flag"]["Category"],
                                   state="hidden",
                                   max_attempts=0)

            db.session.add(challenge)
            db.session.commit()
        challenge_id = challenge.id

        if challenge.state == "locked":
            db.session.close()
            abort(403)

        if challenge.requirements:
            requirements = challenge.requirements.get("prerequisites", [])
            solve_ids = (Solves.query.with_entities(
                Solves.challenge_id).filter_by(
                    account_id=user.account_id).order_by(
                        Solves.challenge_id.asc()).all())
            solve_ids = set([solve_id for solve_id, in solve_ids])
            prereqs = set(requirements)
            if solve_ids >= prereqs:
                pass
            else:
                db.session.close()
                abort(403)

        chal_class = get_chal_class(challenge.type)

        if kpm > 10:
            if ctftime():
                chal_class.fail(user=user,
                                team=team,
                                challenge=challenge,
                                request=request)
            log(
                "submissions",
                "[{date}] {name} submitted {submission} on {challenge_id} with kpm {kpm} [TOO FAST]",
                submission=request_data.get("submission", "").encode("utf-8"),
                challenge_id=challenge_id,
                kpm=kpm,
            )
            # Submitting too fast
            db.session.close()
            return (
                {
                    "success": True,
                    "data": {
                        "status": "ratelimited",
                        "message":
                        "You're submitting flags too fast. Slow down.",
                    },
                },
                429,
            )

        solves = Solves.query.filter_by(account_id=user.account_id,
                                        challenge_id=challenge_id).first()

        # Challenge not solved yet
        if not solves:
            status, message = chal_class.attempt(challenge, request)
            chal_class.solve(user=user,
                             team=team,
                             challenge=challenge,
                             request=request)
            clear_standings()
            log(
                "submissions",
                "[{date}] {name} submitted {submission} on {challenge_id} via flaganizer with kpm {kpm} [CORRECT]",
                submission=request_data.get("submission", "").encode("utf-8"),
                challenge_id=challenge_id,
                kpm=kpm,
            )
            db.session.close()
            return {
                "success": True,
                "data": {
                    "status": "correct",
                    "message": "Successfully submitted!"
                },
            }
        else:
            log(
                "submissions",
                "[{date}] {name} submitted {submission} on {challenge_id} via flaganizer with kpm {kpm} [ALREADY SOLVED]",
                submission=request_data.get("submission", "").encode("utf-8"),
                challenge_id=challenge_id,
                kpm=kpm,
            )
            db.session.close()
            return {
                "success": True,
                "data": {
                    "status": "already_solved",
                    "message": "You already solved this",
                },
            }
Beispiel #9
0
def load(app):
    register_plugin_assets_directory(app, base_path='/plugins/ctfd-event-countdown/assets/')
    register_plugin_script('/plugins/ctfd-event-countdown/assets/countdown.js')
    app.jinja_env.globals.update(ctf_starts_in=ctf_starts_in)
    app.jinja_env.globals.update(ctf_ends_in=ctf_ends_in)
Beispiel #10
0
def load(app):
    # Create new anonymous_challenge table if necessary
    app.db.create_all()

    # Register new challenge type
    CHALLENGE_CLASSES["anonymous"] = CTFdAnonymousChallenge

    # Register plugin assets
    register_plugin_assets_directory(
        app, base_path='/plugins/ctfd_anonymousChallenges/assets/')
    register_plugin_script(
        '/plugins/ctfd_anonymousChallenges/assets/anonymous-challenge-submit.js'
    )

    # Register custom route to check submissions

    @app.route('/anonchal', methods=['POST'])
    @during_ctf_time_only
    @viewable_without_authentication()
    def anonchal():
        if utils.ctf_paused():
            return jsonify({
                'status': 3,
                'message': '{} is paused'.format(utils.ctf_name())
            })

        if utils.is_admin() or (utils.authed() and utils.is_verified() and
                                (utils.ctf_started()
                                 or utils.view_after_ctf())):

            team = Teams.query.filter_by(id=session['id']).first()
            provided_key = request.form['key'].strip()
            logger = logging.getLogger('keys')
            data = (time.strftime("%m/%d/%Y %X"),
                    session['username'].encode('utf-8'),
                    provided_key.encode('utf-8'), utils.get_kpm(session['id']))

            # Anti-bruteforce / KPM is based on last failed key (not logged), so sleep instead.
            time.sleep(2)

            # Find challenge by looking up the provided flag
            key = db.session.query(Keys).\
                join(AnonymousChallenge).\
                filter(Keys.flag == provided_key).first()

            if not key:
                logger.info(
                    "[{0}] {1} submitted {2} with kpm {3} [WRONG]".format(
                        *data))
                return jsonify({'status': 0, 'message': 'Invalid Flag'})

            chal = AnonymousChallenge.query.filter_by(id=key.chal).first()

            chal_class = get_chal_class(chal.type)
            solves = Solves.query.filter_by(teamid=session['id'],
                                            chalid=chal.id).first()

            # If team hasn't solved challenge yet, save the solve
            if not solves:
                # We already know the flag is correct because we checked it already
                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': "Correct"})

            # Otherwise, raise an error
            else:
                logger.info(
                    "{0} submitted {1} with kpm {2} [ALREADY SOLVED]".format(
                        *data))
                return jsonify({
                    'status': 2,
                    'message': 'You already solved this'
                })
        else:
            return jsonify({
                'status':
                -1,
                'message':
                "You must be logged in to solve a challenge"
            })