def update_user(user): session["id"] = user.id session["hash"] = hmac(user.password) session.permanent = True # Clear out any currently cached user attributes clear_user_session(user_id=user.id)
def update_user(user): session["id"] = user.id session["name"] = user.name session["email"] = user.email session["hash"] = hmac(user.password) # Clear out any currently cached user attributes clear_user_session(user_id=user.id)
def test_dynamic_challenge_loses_value_properly(): app = create_ctfd(enable_plugins=True) with app.app_context(): register_user(app) client = login_as_user(app, name="admin", password="******") challenge_data = { "name": "name", "category": "category", "description": "description", "value": 500, "initial": 500, "slope": 1.5, "decrease": 2.079, "state": "visible", "type": "dynamic", } r = client.post("/api/v1/challenges", json=challenge_data) assert r.get_json().get("data")["id"] == 1 gen_flag(app.db, challenge_id=1, content="flag") for i, team_id in enumerate(range(2, 26)): name = "user{}".format(team_id) email = "user{}@ctfd.io".format(team_id) # We need to bypass rate-limiting so gen_user instead of register_user user = gen_user(app.db, name=name, email=email) user_id = user.id with app.test_client() as client: # We need to bypass rate-limiting so creating a fake user instead of logging in with client.session_transaction() as sess: sess["id"] = user_id sess["nonce"] = "fake-nonce" sess["hash"] = hmac(user.password) data = {"submission": "flag", "challenge_id": 1} r = client.post("/api/v1/challenges/attempt", json=data) resp = r.get_json()["data"] assert resp["status"] == "correct" chal = DynamicChallenge.query.filter_by(id=1).first() assert chal.initial >= chal.value if i == 0: # The first solver should get the maximum points assert chal.initial == chal.value elif i == 10: # The value should be around half of the maximum by 10 solvers assert chal.value > 260 assert chal.value < 270 elif i == 250: assert chal.value > 95 assert chal.value < 105 destroy_ctfd(app)
def test_dynamic_challenge_value_isnt_affected_by_hidden_users(): app = create_ctfd(enable_plugins=True) with app.app_context(): register_user(app) client = login_as_user(app, name="admin", password="******") challenge_data = { "name": "name", "category": "category", "description": "description", "value": 100, "decay": 20, "minimum": 1, "state": "visible", "type": "dynamic", } r = client.post("/api/v1/challenges", json=challenge_data) assert r.get_json().get("data")["id"] == 1 gen_flag(app.db, challenge_id=1, content="flag") # Make a solve as a regular user. This should not affect the value. data = {"submission": "flag", "challenge_id": 1} r = client.post("/api/v1/challenges/attempt", json=data) resp = r.get_json()["data"] assert resp["status"] == "correct" # Make solves as hidden users. Also should not affect value for i, team_id in enumerate(range(2, 26)): name = "user{}".format(team_id) email = "user{}@ctfd.io".format(team_id) # We need to bypass rate-limiting so gen_user instead of register_user user = gen_user(app.db, name=name, email=email) user.hidden = True app.db.session.commit() user_id = user.id with app.test_client() as client: # We need to bypass rate-limiting so creating a fake user instead of logging in with client.session_transaction() as sess: sess["id"] = user_id sess["nonce"] = "fake-nonce" sess["hash"] = hmac(user.password) data = {"submission": "flag", "challenge_id": 1} r = client.post("/api/v1/challenges/attempt", json=data) assert r.status_code == 200 resp = r.get_json()["data"] assert resp["status"] == "correct" chal = DynamicChallenge.query.filter_by(id=1).first() assert chal.value == chal.initial destroy_ctfd(app)
def get_current_user(): if authed(): user = Users.query.filter_by(id=session["id"]).first() # Check if the session is still valid session_hash = session.get("hash") if session_hash: if session_hash != hmac(user.password): logout_user() abort(redirect(url_for("auth.login", next=request.full_path))) return user else: return None
def test_dynamic_challenge_loses_value_properly(): app = create_ctfd(enable_plugins=True) with app.app_context(): register_user(app) client = login_as_user(app, name="admin", password="******") challenge_data = { "name": "name", "category": "category", "description": "description", "value": 100, "decay": 20, "minimum": 1, "state": "visible", "type": "dynamic", } r = client.post("/api/v1/challenges", json=challenge_data) assert r.get_json().get("data")["id"] == 1 gen_flag(app.db, challenge_id=1, content="flag") for i, team_id in enumerate(range(2, 26)): name = "user{}".format(team_id) email = "user{}@examplectf.com".format(team_id) # We need to bypass rate-limiting so gen_user instead of register_user user = gen_user(app.db, name=name, email=email) user_id = user.id with app.test_client() as client: # We need to bypass rate-limiting so creating a fake user instead of logging in with client.session_transaction() as sess: sess["id"] = user_id sess["nonce"] = "fake-nonce" sess["hash"] = hmac(user.password) data = {"submission": "flag", "challenge_id": 1} r = client.post("/api/v1/challenges/attempt", json=data) resp = r.get_json()["data"] assert resp["status"] == "correct" chal = DynamicChallenge.query.filter_by(id=1).first() if i >= 20: assert chal.value == chal.minimum else: assert chal.initial >= chal.value assert chal.value > chal.minimum destroy_ctfd(app)
def get_invite_code(self): from flask import current_app from CTFd.utils.security.signing import serialize, hmac secret_key = current_app.config["SECRET_KEY"] if isinstance(secret_key, str): secret_key = secret_key.encode("utf-8") team_password_key = self.password.encode("utf-8") verification_secret = secret_key + team_password_key invite_object = { "id": self.id, "v": hmac(str(self.id), secret=verification_secret), } code = serialize(data=invite_object, secret=secret_key) return code
def load_invite_code(cls, code): from flask import current_app from CTFd.utils.security.signing import ( unserialize, hmac, BadTimeSignature, BadSignature, ) from CTFd.exceptions import TeamTokenExpiredException, TeamTokenInvalidException secret_key = current_app.config["SECRET_KEY"] if isinstance(secret_key, str): secret_key = secret_key.encode("utf-8") # Unserialize the invite code try: # Links expire after 1 day invite_object = unserialize(code, max_age=86400) except BadTimeSignature: raise TeamTokenExpiredException except BadSignature: raise TeamTokenInvalidException # Load the team by the ID in the invite team_id = invite_object["id"] team = cls.query.filter_by(id=team_id).first_or_404() # Create the team specific secret team_password_key = team.password.encode("utf-8") verification_secret = secret_key + team_password_key # Verify the team verficiation code verified = hmac(str(team.id), secret=verification_secret) == invite_object["v"] if verified is False: raise TeamTokenInvalidException return team