18
18
HMAC_SECRET = os .environ ["HMAC_SECRET" ].encode ("utf-8" )
19
19
API_URL = os .environ ["API_URL" ]
20
20
21
+ # This will be "open" or "closed", which determins how email address that don't exist in the
22
+ # registrants table are handled.
23
+ REGISTRATION_MODE = os .environ ["REGISTRATION_MODE" ].lower ()
24
+
21
25
22
26
def sign_payload (data ):
23
27
sig = hmac .new (HMAC_SECRET , data .encode ("utf-8" ),
@@ -56,6 +60,9 @@ def post(event, contest):
56
60
57
61
try :
58
62
username = event ["username" ]
63
+ # In closed registration, this may pre-assigned, but we still want to ask for a username
64
+ # so we can let them down and confuse the registrants. :)
65
+ display_name = username
59
66
except :
60
67
return {"result" : "failure" }
61
68
@@ -79,25 +86,48 @@ def post(event, contest):
79
86
"S" : email
80
87
}})
81
88
82
- # If the DDB item doesn't exist, or if it does and it hasn't yet been assigned a team ID
83
- # then there is no duplicate problem.
84
- if "Item" in item and "teamId" in item ["Item" ]:
85
- return {"result" : "failed_duplicate" }
89
+ # Registrations are duplicates if the email exists in the DDB table, and the "confirmationTime" column
90
+ # doesn't yet have a timestamp.
91
+ #
92
+ # Obvious, if the item is missing, the get_item() call returns no Item key.
93
+ if "Item" in item :
94
+ # Regardless of registration mode, if there is a confirmed registration for this email,
95
+ # don't permit another.
96
+ if "confirmationTime" in item ["Item" ]:
97
+ return {"result" : "failed_duplicate" }
98
+ else :
99
+ # This is the case where the email exists, in which case the registration mode matters.
100
+
101
+ # The default behaviour is open registration.
102
+ # For closed registration, they needn't have a team ID, but they might, so if they do
103
+ # have one from the table already, use that.
104
+ if REGISTRATION_MODE == "closed" :
105
+ team_id = int (item ["Item" ].get ("team_id" , {"N" : team_id })["N" ])
106
+ display_name = item ["Item" ].get ("display_name" , username )["S" ]
107
+ else : # REGISTRATION_MODE == "open", or any other value.
108
+ pass
109
+ else :
110
+ # In the case of closed registration, every email that tries to register must be part of
111
+ # the table already. If it isn't, it gets an "unauthorized" error response, but to prevent
112
+ # people trying to credential-stuff, we'll just say "unknown". 😺
113
+ if REGISTRATION_MODE == "closed" :
114
+ return {"result" : "failed_unknown" }
86
115
87
116
confirmation_payload = {
88
117
"email" : email ,
89
118
"username" : username ,
90
119
"teamId" : team_id ,
91
- "registrationTime" : time .time ()
120
+ "registrationTime" : time .time (),
121
+ "display_name" : display_name
92
122
}
93
123
94
124
confirmation_token = sign_payload (json .dumps (confirmation_payload ))
95
125
96
126
ses .send_email (Destination = {"ToAddresses" : [email ]},
97
- Source = "The Big Kahuna CTF <ctf@example.com>" ,
127
+ Source = "CTF Registration <%s>" % os . environ [ "SES_EMAIL_SOURCE" ] ,
98
128
Message = {
99
129
"Subject" : {
100
- "Data" : "The Big Kahuna CTF - Confirm your email"
130
+ "Data" : "CTF Registration - Confirm your email"
101
131
},
102
132
"Body" : {
103
133
"Html" : {
@@ -130,9 +160,9 @@ def post(event, contest):
130
160
<body class="vscode-light">
131
161
<h1 id="ctf-registration">CTF Registration - Confirm your email</h1>
132
162
<p>You've taken the first step towards registering in the CTF. We just need you to confirm your email, and we'll be on our way.</p>
133
- <p>Click the <a href="%s">here</a> to confirm your registration.</p>
163
+ <p>Click <a href="%s">here</a> to confirm your registration.</p>
134
164
<p>See you soon!</p>
135
- <p>The Big Kahuna CTF Team</p>
165
+ <p>The CTF Team</p>
136
166
</body>
137
167
</html>
138
168
""" %
@@ -159,6 +189,7 @@ def get_confirm(event, context):
159
189
email = registration_payload ["email" ]
160
190
team_id = registration_payload ["teamId" ]
161
191
username = registration_payload ["username" ]
192
+ display_name = registration_payload ["display_name" ]
162
193
registration_time = registration_payload ["registrationTime" ]
163
194
164
195
ddb .put_item (TableName = event ["RegistrantsTable" ],
@@ -169,6 +200,9 @@ def get_confirm(event, context):
169
200
"username" : {
170
201
"S" : username
171
202
},
203
+ "display_name" : {
204
+ "S" : display_name
205
+ },
172
206
"teamId" : {
173
207
"N" : str (team_id )
174
208
},
@@ -181,53 +215,61 @@ def get_confirm(event, context):
181
215
})
182
216
183
217
ses .send_email (Destination = {"ToAddresses" : [email ]},
184
- Source = "The Big Kahuna CTF <ctf@example.com>" ,
218
+ Source = "CTF Registration <%s>" % os . environ [ "SES_EMAIL_SOURCE" ] ,
185
219
Message = {
186
220
"Subject" : {
187
- "Data" : "The Big Kahuna CTF Registration"
221
+ "Data" : "CTF Registration - Complete! "
188
222
},
189
223
"Body" : {
190
224
"Html" : {
191
225
"Charset" :
192
226
"utf-8" ,
193
227
"Data" :
194
- """
228
+ f """
195
229
<!DOCTYPE html>
196
230
<html>
197
- <head>
198
- <meta charset="UTF-8">
199
- <title>CTF Registration</title>
200
-
201
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/Microsoft/vscode/extensions/markdown-language-features/media/markdown.css">
202
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/Microsoft/vscode/extensions/markdown-language-features/media/highlight.css">
203
231
204
- <style>
205
- .task-list-item { list-style-type: none; } .task-list-item-checkbox { margin-left: -20px; vertical-align: middle; }
206
- </style>
207
- <style>
208
- body {
209
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe WPC', 'Segoe UI', 'Ubuntu', 'Droid Sans', sans-serif;
210
- font-size: 14px;
211
- line-height: 1.6;
212
- }
213
- </style>
214
-
215
- </head>
216
- <body class="vscode-light">
217
- <h1 id="ctf-registration">CTF Registration</h1>
218
- <p>Congratulations %s! You've signed up for our CTF, The Big Kahuna CTF!</p>
219
- <ul>
220
- <li>When submitting your flags, your team ID is %d and you will show up as "%s" on the scores list</li>
221
- <li>To submit flags, head over to <a href="https://ctf.example.com/submit">https://ctf.example.com/submit</a></li>
222
- <li>To view the current standings, head over to <a href="https://ctf.example.com/scores">https://ctf.example.com/scores</a></li>
223
- </ul>
224
- <p>Enjoy and godspeed!</p>
225
- <p>Best wishes,
226
- The Big Kahuna CTF Team</p>
227
-
228
- </body>
229
- </html>
230
- """ % (username , team_id , username )
232
+ <body>
233
+ <h1>Welcome to the 2019 CCDC event!</h1>
234
+ <p>To get you started, here's some important information and references. <ul>
235
+ <li>Your team name is "{ display_name } "", and we have auto-generated a team ID for your team.</li>
236
+ <li>Your team ID is { team_id } </li>
237
+ <li>You'll need this team ID when submitting flags, <i>don't lose this</i>! To submit flags, you will need
238
+ to use the <a href="https://ccdc.zone/scores/submit">flag submission page</a>. </li>
239
+ <li>To see the scoreboard, go to the <a href="https://ccdc.zone/scores/dashboard">score dashboard</a></li>
240
+ <li>This team ID is unique to your team, so don't share it with members of other teams.</li>
241
+ </ul>
242
+ </p>
243
+ <p>Your team has been allocated an environment for today, complete with targets, as well as VMs for you to remote
244
+ into that will contain all of the tools you will need today. You can find your team's starting package <a
245
+ href="https://ccdc.zone/packages/{ team_id } .zip">here</a>. <ul>
246
+ <li>This package contains passwords, private keys, hostnames, and other information to get you and your
247
+ teammates started.</li>
248
+ <li>Inside of the zip package, you'll see a few files that start with the word `jumpbox`. These files
249
+ contain the details for access your team's jumpboxes (<a target="_blank"
250
+ href="https://en.wikipedia.org/wiki/Jump_server">Ref</a>). There are 5 jumpboxes for your team, so
251
+ you and your teammates can decide who gets which jumpbox (they are numbered for your convenience). </li>
252
+ <li><b>THE JUMP BOXES ARE NOT IN SCOPE OF THE EVENT.</b> They are provided as ready-made environments,
253
+ complete with all of the tools you will need during the event. If there are tools you want to use that
254
+ are not installed in the jumpboxes, you are welcome to install them (you have full Administrator
255
+ credentials to these jumpboxes), however <i>you do so at your own risk</i>. <b>IF YOU LOCK YOURSELF OUT
256
+ OF YOUR JUMPBOX, WE WILL NOT PROVISION A NEW ONE AND YOU WILL NEED TO DEPEND ON YOUR TEAMMATES</b>.
257
+ </li>
258
+ <li>To access your chosen jumpbox, you will need to RDP into it using the hostname and credentials in the
259
+ corresponding file. Microsoft has documentation on how their applications (<a target="_blank"
260
+ href="https://docs.microsoft.com/en-us/windows-server/remote/remote-desktop-services/clients/remote-desktop-clients">Ref</a>),
261
+ and for those on Linux we recommend using the <a target="_blank" href="https://remmina.org/">Remmina
262
+ remote desktop client</a>.</li>
263
+ </ul>
264
+ </p>
265
+ <p> This should be enough to get you started, but you will need to read the <a href="https://ccdc.zone/documentation">official
266
+ complete documentation</a> for all of the information you will need to be successful today. </p>
267
+ <h2>Keep your email inbox open or notifications turned on, as we may be sending updates, hints, and notifications to
268
+ you by email throughout the day.</h2>
269
+
270
+ </html>
271
+ </body>
272
+ """
231
273
}
232
274
}
233
275
})
@@ -237,10 +279,11 @@ def get_confirm(event, context):
237
279
238
280
def get (event , contest ):
239
281
items = ddb .scan (TableName = event ["RegistrantsTable" ])
282
+ pairs = set ([(item ["teamId" ]["N" ], item ["display_name" ]["S" ]) for item in items .get ("Items" , [])])
240
283
return [{
241
- "team_id" : item [ "teamId" ][ "N" ],
242
- "team_name" : item [ "username" ][ "S" ]
243
- } for item in items . get ( "Items" , []) ]
284
+ "team_id" : t [ 0 ],
285
+ "team_name" : t [ 1 ]
286
+ } for t in pairs ]
244
287
245
288
246
289
def lambda_handler (event , context ):
0 commit comments