From ec83eb1130d6cad8122ada3347c082b9a63eba54 Mon Sep 17 00:00:00 2001 From: bWlrYQ Date: Fri, 6 Sep 2024 18:26:46 +0200 Subject: [PATCH 1/4] Fix RECaptcha not being disabled even when value is set to 0 in .env --- app/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/app.py b/app/app.py index 9003780..770274f 100644 --- a/app/app.py +++ b/app/app.py @@ -16,7 +16,7 @@ def create_app(): app.config["SQLALCHEMY_DATABASE_URI"] = getenv("DATABASE_URI") app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False - app.config["ENABLE_RECAPTCHA"] = getenv("ENABLE_RECAPTCHA", False) + app.config["ENABLE_RECAPTCHA"] = getenv("ENABLE_RECAPTCHA", False) in ["1", "True", "TRUE"] app.config["RECAPTCHA_SITE_KEY"] = getenv("RECAPTCHA_SITE_KEY", "") app.config["RECAPTCHA_SECRET_KEY"] = getenv("RECAPTCHA_SECRET_KEY", "") From 4209e5b18b2be62c71ee724f98abe38e93f5d106 Mon Sep 17 00:00:00 2001 From: bWlrYQ Date: Fri, 6 Sep 2024 18:27:30 +0200 Subject: [PATCH 2/4] Fix improper variable name in app.py causing the app to crash when deploying a container for a user --- app.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app.py b/app.py index 15293ad..c6d586f 100644 --- a/app.py +++ b/app.py @@ -222,8 +222,8 @@ def run_instance(): flash("The challenge name is not valid.", "red") return redirect(url_for('index')) - if get_challenge_count_per_team(session["team_id"]) >= MAX_CHALLENGES_PER_TEAM: - flash(f"Your team has reached the maximum number of concurrent running instances ({MAX_CHALLENGES_PER_TEAM}).", "red") + if get_challenge_count_per_team(session["team_id"]) >= MAX_INSTANCE_PER_TEAM: + flash(f"Your team has reached the maximum number of concurrent running instances ({MAX_INSTANCE_PER_TEAM}).", "red") return redirect(url_for('index')) remove_user_running_instance(session["user_id"]) From 216a3d231b12d224debe63f35d08ce544ac6afa2 Mon Sep 17 00:00:00 2001 From: bWlrYQ Date: Fri, 6 Sep 2024 18:32:43 +0200 Subject: [PATCH 3/4] add the ability to launch containers even in solo mode, until now it was only teams mode on CTFd --- app/utils.py | 47 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/app/utils.py b/app/utils.py index 959eda1..b5c619f 100644 --- a/app/utils.py +++ b/app/utils.py @@ -190,6 +190,25 @@ def check_challenge_name(challenge_name): return True return False +def check_mode(key): + """ + Returns the mode of the CTFd instance (teams or user) + """ + base_url = CTFD_URL.strip('/') + try: + req = requests.get(f"{base_url}/api/v1/teams", + headers={"Authorization":f"Token {key}", "Content-Type": "application/json"}) + # If /api/v1/teams endpoint is accessible, then CTF mode is teams, otherwise if 404 it's user. Dirty but works. + if req.status_code == 200: + return "teams" + elif req.status_code == 404: + return "user" + else: + return False + except Exception as err: + current_app.logger.error(f"Error checking mode: {err}") + current_app.logger.error("Error: %s", err) + return False def check_access_key(key): """ @@ -202,7 +221,7 @@ def check_access_key(key): "team_name": None, "is_admin": False } - + pattern = r'^ctfd_[a-zA-Z0-9]+$' if not re.match(pattern, key): return False, "Invalid access key, wrong format!", user @@ -215,18 +234,30 @@ def check_access_key(key): success = resp_json.get("success", False) user["user_id"] = resp_json.get("data", {}).get("id", "") user["username"] = resp_json.get("data", {}).get("name", "") - user["team_id"] = resp_json.get("data", {}).get("team_id", False) - # User is not in a team - if not success or not user["team_id"]: - return False, "User not in a team or invalid token.", user + mode = check_mode(key) + current_app.logger.error(mode) + + if mode == "teams": + user["team_id"] = resp_json.get("data", {}).get("team_id", False) - resp_json = requests.get(f"{base_url}/api/v1/teams/{user['team_id']}", - headers={"Authorization":f"Token {key}", "Content-Type":"application/json"}).json() - user["team_name"] = resp_json.get("data", {}).get("name", "") + # User is not in a team + if not success or not user["team_id"]: + return False, "User not in a team or invalid token.", user + + resp_json = requests.get(f"{base_url}/api/v1/teams/{user['team_id']}", + headers={"Authorization":f"Token {key}", "Content-Type":"application/json"}).json() + user["team_name"] = resp_json.get("data", {}).get("name", "") + # Easy workaround to keep the app working even in solo mode is to emulate a fake team based on user id and username :) + elif mode == "user": + user["team_id"] = resp_json.get("data", {}).get("id", "") + user["team_name"] = resp_json.get("data", {}).get("name", "") + else: + return False, "An error occurred while checking the CTF mode" resp_json = requests.get(f"{base_url}/api/v1/configs", headers={"Authorization":f"Token {key}", "Content-Type":"application/json"}).json() user["is_admin"] = resp_json.get("success", False) + return True, "", user except Exception as err: current_app.logger.error("Unable to reach CTFd with access key: %s", key) From d5cd162384eac913b748c367ac9ccc8ea1bd5bab Mon Sep 17 00:00:00 2001 From: bWlrYQ <77877894+bWlrYQ@users.noreply.github.com> Date: Fri, 6 Sep 2024 18:52:37 +0200 Subject: [PATCH 4/4] Apply pimpmyshell's fix for RECaptcha --- app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.py b/app.py index c6d586f..df63994 100644 --- a/app.py +++ b/app.py @@ -208,7 +208,7 @@ def run_instance(): challenge_name = request.form.get("challenge_name", None) # Disable captcha on debug mode - if not current_app.config["ENABLE_RECAPTCHA"] and not recaptcha.verify(): + if not current_app.config["DEBUG"] and current_app.config["ENABLE_RECAPTCHA"] and not recaptcha.verify(): flash("Captcha failed.", "red") return redirect(url_for('index'))