def during_ctf_time_only_wrapper(*args, **kwargs): if ctftime() or current_user.is_admin(): return f(*args, **kwargs) else: if ctf_ended(): if view_after_ctf(): return f(*args, **kwargs) else: error = "{} has ended".format(config.ctf_name()) abort(403, description=error) if ctf_started() is False: error = "{} has not started yet".format(config.ctf_name()) abort(403, description=error)
def export_ctf(): backup = export_ctf_util() ctf_name = ctf_config.ctf_name() day = datetime.datetime.now().strftime("%Y-%m-%d") full_name = u"{}.{}.zip".format(ctf_name, day) return send_file( backup, cache_timeout=-1, as_attachment=True, attachment_filename=full_name )
def export_csv(): table = request.args.get("table") # TODO: It might make sense to limit dumpable tables. Config could potentially leak sensitive information. model = get_class_by_tablename(table) if model is None: abort(404) temp = six.StringIO() writer = csv.writer(temp) header = [column.name for column in model.__mapper__.columns] writer.writerow(header) responses = model.query.all() for curr in responses: writer.writerow( [getattr(curr, column.name) for column in model.__mapper__.columns] ) temp.seek(0) # In Python 3 send_file requires bytes output = six.BytesIO() output.write(temp.getvalue().encode("utf-8")) output.seek(0) temp.close() return send_file( output, as_attachment=True, cache_timeout=-1, attachment_filename="{name}-{table}.csv".format( name=ctf_config.ctf_name(), table=table ), )
def post(self): 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() challenge_id = request_data.get("challenge_id") if current_user.is_admin(): preview = request.args.get("preview", False) if preview: challenge = Challenges.query.filter_by( id=challenge_id).first_or_404() chal_class = get_chal_class(challenge.type) status, message = chal_class.attempt(challenge, request) return { "success": True, "data": { "status": "correct" if status else "incorrect", "message": message, }, } 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) fails = Fails.query.filter_by(account_id=user.account_id, challenge_id=challenge_id).count() challenge = Challenges.query.filter_by(id=challenge_id).first_or_404() if challenge.state == "hidden": abort(404) if challenge.state == "locked": 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: abort(403) chal_class = get_chal_class(challenge.type) # Anti-bruteforce / submitting Flags too quickly kpm = current_user.get_wrong_submissions_per_minute(user.account_id) 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["submission"].encode("utf-8"), challenge_id=challenge_id, kpm=kpm, ) # Submitting too fast 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: # Hit max attempts max_tries = challenge.max_attempts if max_tries and fails >= max_tries > 0: return ( { "success": True, "data": { "status": "incorrect", "message": "You have 0 tries remaining", }, }, 403, ) status, message = chal_class.attempt(challenge, request) if status: # The challenge plugin says the input is right if ctftime() or current_user.is_admin(): chal_class.solve(user=user, team=team, challenge=challenge, request=request) clear_standings() log( "submissions", "[{date}] {name} submitted {submission} on {challenge_id} with kpm {kpm} [CORRECT]", submission=request_data["submission"].encode("utf-8"), challenge_id=challenge_id, kpm=kpm, ) return { "success": True, "data": { "status": "correct", "message": message }, } else: # The challenge plugin says the input is wrong if ctftime() or current_user.is_admin(): chal_class.fail(user=user, team=team, challenge=challenge, request=request) clear_standings() log( "submissions", "[{date}] {name} submitted {submission} on {challenge_id} with kpm {kpm} [WRONG]", submission=request_data["submission"].encode("utf-8"), challenge_id=challenge_id, kpm=kpm, ) if max_tries: # Off by one since fails has changed since it was gotten attempts_left = max_tries - fails - 1 tries_str = "tries" if attempts_left == 1: tries_str = "try" # Add a punctuation mark if there isn't one if message[-1] not in "!().;?[]{}": message = message + "." return { "success": True, "data": { "status": "incorrect", "message": "{} You have {} {} remaining.".format( message, attempts_left, tries_str), }, } else: return { "success": True, "data": { "status": "incorrect", "message": message }, } # Challenge already solved else: log( "submissions", "[{date}] {name} submitted {submission} on {challenge_id} with kpm {kpm} [ALREADY SOLVED]", submission=request_data["submission"].encode("utf-8"), challenge_id=challenge_id, kpm=kpm, ) return { "success": True, "data": { "status": "already_solved", "message": "You already solved this", }, }
from KMActf import create_app from KMActf.utils import config from KMActf.utils.exports import export_ctf import datetime import sys import shutil app = create_app() with app.app_context(): backup = export_ctf() if len(sys.argv) > 1: with open(sys.argv[1], "wb") as target: shutil.copyfileobj(backup, target) else: ctf_name = config.ctf_name() day = datetime.datetime.now().strftime("%Y-%m-%d") full_name = "{}.{}.zip".format(ctf_name, day) with open(full_name, "wb") as target: shutil.copyfileobj(backup, target) print("Exported {filename}".format(filename=full_name))