109 lines
3.7 KiB
Python
109 lines
3.7 KiB
Python
from flask import Blueprint
|
|
|
|
from CTFd.models import (
|
|
db,
|
|
Flags,
|
|
)
|
|
from CTFd.plugins.challenges import BaseChallenge
|
|
from CTFd.plugins.dynamic_challenges import DynamicValueChallenge
|
|
from CTFd.plugins.flags import get_flag_class
|
|
from CTFd.utils import user as current_user
|
|
from .models import WhaleContainer, DynamicDockerChallenge
|
|
from .utils.control import ControlUtil
|
|
|
|
|
|
class DynamicValueDockerChallenge(BaseChallenge):
|
|
id = "dynamic_docker" # Unique identifier used to register challenges
|
|
name = "dynamic_docker" # Name of a challenge type
|
|
# Blueprint used to access the static_folder directory.
|
|
blueprint = Blueprint(
|
|
"ctfd-whale-challenge",
|
|
__name__,
|
|
template_folder="templates",
|
|
static_folder="assets",
|
|
)
|
|
challenge_model = DynamicDockerChallenge
|
|
|
|
@classmethod
|
|
def read(cls, challenge):
|
|
challenge = DynamicDockerChallenge.query.filter_by(id=challenge.id).first()
|
|
data = {
|
|
"id": challenge.id,
|
|
"name": challenge.name,
|
|
"value": challenge.value,
|
|
"initial": challenge.initial,
|
|
"decay": challenge.decay,
|
|
"minimum": challenge.minimum,
|
|
"description": challenge.description,
|
|
"category": challenge.category,
|
|
"state": challenge.state,
|
|
"max_attempts": challenge.max_attempts,
|
|
"type": challenge.type,
|
|
"type_data": {
|
|
"id": cls.id,
|
|
"name": cls.name,
|
|
"templates": cls.templates,
|
|
"scripts": cls.scripts,
|
|
},
|
|
}
|
|
return data
|
|
|
|
@classmethod
|
|
def update(cls, challenge, request):
|
|
data = request.form or request.get_json()
|
|
|
|
for attr, value in data.items():
|
|
# We need to set these to floats so that the next operations don't operate on strings
|
|
if attr in ("initial", "minimum", "decay"):
|
|
value = float(value)
|
|
if attr == 'dynamic_score':
|
|
value = int(value)
|
|
setattr(challenge, attr, value)
|
|
|
|
if challenge.dynamic_score == 1:
|
|
return DynamicValueChallenge.calculate_value(challenge)
|
|
|
|
db.session.commit()
|
|
return challenge
|
|
|
|
@classmethod
|
|
def attempt(cls, challenge, request):
|
|
data = request.form or request.get_json()
|
|
submission = data["submission"].strip()
|
|
|
|
flags = Flags.query.filter_by(challenge_id=challenge.id).all()
|
|
|
|
if len(flags) > 0:
|
|
for flag in flags:
|
|
if get_flag_class(flag.type).compare(flag, submission):
|
|
return True, "Correct"
|
|
return False, "Incorrect"
|
|
else:
|
|
user_id = current_user.get_current_user().id
|
|
q = db.session.query(WhaleContainer)
|
|
q = q.filter(WhaleContainer.user_id == user_id)
|
|
q = q.filter(WhaleContainer.challenge_id == challenge.id)
|
|
records = q.all()
|
|
if len(records) == 0:
|
|
return False, "Please solve it during the container is running"
|
|
|
|
container = records[0]
|
|
if container.flag == submission:
|
|
return True, "Correct"
|
|
return False, "Incorrect"
|
|
|
|
@classmethod
|
|
def solve(cls, user, team, challenge, request):
|
|
super().solve(user, team, challenge, request)
|
|
|
|
if challenge.dynamic_score == 1:
|
|
DynamicValueChallenge.calculate_value(challenge)
|
|
|
|
@classmethod
|
|
def delete(cls, challenge):
|
|
for container in WhaleContainer.query.filter_by(
|
|
challenge_id=challenge.id
|
|
).all():
|
|
ControlUtil.try_remove_container(container.user_id)
|
|
super().delete(challenge)
|