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)
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")
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!")
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')
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)
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", }, }
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)
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" })