diff --git a/CTFd/plugins/challenges/__init__.py b/CTFd/plugins/challenges/__init__.py index d6de41aa..9c55289c 100644 --- a/CTFd/plugins/challenges/__init__.py +++ b/CTFd/plugins/challenges/__init__.py @@ -11,7 +11,7 @@ from CTFd.models import ( db, ) from CTFd.plugins import register_plugin_assets_directory -from CTFd.plugins.flags import get_flag_class +from CTFd.plugins.flags import FlagException, get_flag_class from CTFd.utils.uploads import delete_file from CTFd.utils.user import get_ip @@ -138,8 +138,11 @@ class CTFdStandardChallenge(BaseChallenge): submission = data["submission"].strip() flags = Flags.query.filter_by(challenge_id=challenge.id).all() for flag in flags: - if get_flag_class(flag.type).compare(flag, submission): - return True, "Correct" + try: + if get_flag_class(flag.type).compare(flag, submission): + return True, "Correct" + except FlagException as e: + return False, e.message return False, "Incorrect" @staticmethod diff --git a/CTFd/plugins/dynamic_challenges/__init__.py b/CTFd/plugins/dynamic_challenges/__init__.py index 09a930ba..5e784c10 100644 --- a/CTFd/plugins/dynamic_challenges/__init__.py +++ b/CTFd/plugins/dynamic_challenges/__init__.py @@ -16,7 +16,7 @@ from CTFd.models import ( ) from CTFd.plugins import register_plugin_assets_directory from CTFd.plugins.challenges import CHALLENGE_CLASSES, BaseChallenge -from CTFd.plugins.flags import get_flag_class +from CTFd.plugins.flags import FlagException, get_flag_class from CTFd.plugins.migrations import upgrade from CTFd.utils.modes import get_model from CTFd.utils.uploads import delete_file @@ -184,8 +184,11 @@ class DynamicValueChallenge(BaseChallenge): submission = data["submission"].strip() flags = Flags.query.filter_by(challenge_id=challenge.id).all() for flag in flags: - if get_flag_class(flag.type).compare(flag, submission): - return True, "Correct" + try: + if get_flag_class(flag.type).compare(flag, submission): + return True, "Correct" + except FlagException as e: + return False, e.message return False, "Incorrect" @staticmethod diff --git a/CTFd/plugins/flags/__init__.py b/CTFd/plugins/flags/__init__.py index 687b6ce6..a468d111 100644 --- a/CTFd/plugins/flags/__init__.py +++ b/CTFd/plugins/flags/__init__.py @@ -3,6 +3,14 @@ import re from CTFd.plugins import register_plugin_assets_directory +class FlagException(Exception): + def __init__(self, message): + self.message = message + + def __str__(self): + return self.message + + class BaseFlag(object): name = None templates = {} @@ -55,8 +63,8 @@ class CTFdRegexFlag(BaseFlag): else: res = re.match(saved, provided) # TODO: this needs plugin improvements. See #1425. - except re.error: - return False + except re.error as e: + raise FlagException("Regex parse error occured") from e return res and res.group() == provided diff --git a/tests/users/test_challenges.py b/tests/users/test_challenges.py index d7dcf8d0..2c3f1168 100644 --- a/tests/users/test_challenges.py +++ b/tests/users/test_challenges.py @@ -181,6 +181,29 @@ def test_submitting_correct_regex_case_insensitive_flag(): destroy_ctfd(app) +def test_submitting_invalid_regex_flag(): + """Test that invalid regex flags are errored out to the user""" + app = create_ctfd() + with app.app_context(): + register_user(app) + client = login_as_user(app) + chal = gen_challenge(app.db) + gen_flag( + app.db, + challenge_id=chal.id, + type="regex", + content="**", + data="case_insensitive", + ) + data = {"submission": "FLAG", "challenge_id": chal.id} + r = client.post("/api/v1/challenges/attempt", json=data) + assert r.status_code == 200 + resp = r.get_json()["data"] + assert resp.get("status") == "incorrect" + assert resp.get("message") == "Regex parse error occured" + destroy_ctfd(app) + + def test_submitting_incorrect_flag(): """Test that incorrect flags are incorrect""" app = create_ctfd()