-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy path__init__.py
169 lines (131 loc) · 6.11 KB
/
__init__.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
import os
import json
from flask import render_template, Blueprint
from flask import request, jsonify,session
from CTFd.models import (
Awards,
ChallengeFiles,
Challenges,
Fails,
Flags,
Hints,
Solves,
Tags,
Teams,
db,
)
from .hooks import load_hooks
from .models import CheaterTeams, RedHerringChallenge, Containers
from .utils import generate_flag, create_docker_container
from . import globals
from CTFd.plugins import register_plugin_assets_directory
from CTFd.plugins.migrations import upgrade
from CTFd.plugins.challenges import BaseChallenge, CHALLENGE_CLASSES
from CTFd.plugins.flags import FlagException, get_flag_class, CTFdStaticFlag, FLAG_CLASSES
from CTFd.utils.uploads import delete_file
from CTFd.utils.user import get_current_team, get_current_user
from CTFd.utils.decorators import admins_only
from CTFd.config import Config
PLUGIN_PATH = os.path.dirname(__file__)
CONFIG = json.load(open("{}/config.json".format(PLUGIN_PATH)))
directory_name = PLUGIN_PATH.split(os.sep)[-1] # Get the directory name of this file
red = Blueprint(directory_name, __name__, template_folder="templates")
class RedHerringTypeChallenge(BaseChallenge):
id = "red_herring" # Unique identifier used to register challenges
name = "red_herring" # Name of a challenge type
templates = { # Nunjucks templates used for each aspect of challenge editing & viewing
'create': '/plugins/'+ directory_name +'/assets/create.html', # Used to render the challenge when creating/editing
'update': '/plugins/' + directory_name + '/assets/update.html', # Used to render the challenge when updating
'view': '/plugins/' + directory_name + '/assets/view.html', # Used to render the challenge when viewing
}
scripts = { # Scripts that are loaded when a template is loaded
'create': '/plugins/'+ directory_name +'/assets/create.js', # Used to init the create template JavaScript
'update': '/plugins/'+ directory_name +'/assets/update.js', # Used to init the create template JavaScript
'view': '/plugins/'+ directory_name +'/assets/view.js', # Used to init the create template JavaScript
}
# Route at which files are accessible. This must be registered using register_plugin_assets_directory()
route = '/plugins/'+ directory_name +'/assets/'
challenge_model = RedHerringChallenge
@staticmethod
def create(request):
"""
This method is used to process the challenge creation request.
:param request:
:return:
"""
data = request.form or request.get_json()
challenge = RedHerringChallenge(
name=data['name'],
category=data['category'],
description=data['description'],
value=data['value'],
state=data['state'],
type=data['type'],
dockerfile= data['buildfile']
)
buildfile = data['buildfile']
db.session.add(challenge)
db.session.commit()
# Check if there is teams that are created
teams = Teams.query.all()
if len(teams) > 0:
# Get the last port used
last_container = Containers.query.order_by(Containers.port.desc()).first()
if last_container_port is None:
port = globals.PORT_CONTAINERS_START
else:
port = last_container.port + 1
# For each team, create a flag and a container for the challenge
for team in teams:
generated_flag = generate_flag()
# Generate the container
container_name = create_docker_container(buildfile=buildfile, flag=generated_flag, port=port, challenge_name=challenge.name, team_id=team.id)
# Save the container in the database
container = Containers(name=container_name, port=port, dockerfile=buildfile, challengeid=challenge.id, teamid=team.id)
port += 1
db.session.add(container)
# Save the flag in the database
flag = Flags(challenge_id = challenge.id, type = "red_herring", content = generated_flag, data = team.id)
db.session.add(flag)
db.session.commit()
return challenge
class RedHearingFlag(CTFdStaticFlag):
name = "red_herring"
@staticmethod
def compare(chal_key_obj, provided_flag):
# Get the actual flag to check for the challenge submitted (the function compare() is called for each flag of the challenge)
saved_flag = chal_key_obj.content
# Compare each character in the flag if the team id is the one that is supposed to solve the challenge
curr_team_id = get_current_team().id
if len(saved_flag) != len(provided_flag):
return False
result = 0
for x, y in zip(saved_flag, provided_flag):
result |= ord(x) ^ ord(y)
if result == 0:
# If the flag is correct, we need to check if the team is the one associated with the flag
team_id_needed = chal_key_obj.data
if int(team_id_needed) == int(curr_team_id):
return True
else:
curr_user_id = get_current_user().id
cheater = CheaterTeams(challengeid=chal_key_obj.challenge_id, cheaterid=curr_user_id, cheatteamid=curr_team_id, sharerteamid=team_id_needed, flagid=chal_key_obj.id)
db.session.add(cheater)
return False
else:
return False
@red.route('/admin/red_herring',methods=['GET'])
@admins_only
def show_cheaters():
if request.method == 'GET':
cheaters = CheaterTeams.query.all()
return render_template('red_herring.html', cheaters=cheaters)
def load(app):
globals.initialize()
app.db.create_all() # Create all DB entities
upgrade(plugin_name="red_herring")
CHALLENGE_CLASSES['red_herring'] = RedHerringTypeChallenge
FLAG_CLASSES['red_herring'] = RedHearingFlag
app.register_blueprint(red)
register_plugin_assets_directory(app, base_path='/plugins/'+ directory_name +'/assets/')
load_hooks()