forked from zwade/CTF-Platform
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial release of the CTF Platform based on picoCTF 2013
- Loading branch information
collinpetty
authored and
collinpetty
committed
Aug 26, 2013
1 parent
f11a492
commit 8402f3d
Showing
355 changed files
with
29,030 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
__author__ = "Collin Petty" | ||
__copyright__ = "Carnegie Mellon University" | ||
__license__ = "MIT" | ||
__maintainer__ = ["Collin Petty", "Peter Chapman"] | ||
__credits__ = ["David Brumely", "Collin Petty", "Peter Chapman", "Tyler Nighswander", "Garrett Barboza"] | ||
__email__ = ["[email protected]", "[email protected]"] | ||
__status__ = "Production" | ||
|
||
from common import db | ||
import common | ||
import group | ||
|
||
import bcrypt | ||
|
||
|
||
def register_team(request): | ||
"""Register a new team. | ||
Checks that an email address, team name, adviser name, affiliation, and password were sent from the browser. | ||
If any of these are missing a status:0 is returned with a message saying that all fields must be provided. | ||
Verifies that no teams exist with the specified name, if one exists a status:0 with a message is returned. | ||
If the 'joingroup' flag is empty or false and the passed 'group' is not empty we check to see if a group with that | ||
name exists in the database, if it does we return a status:2 and a message saying the the group exists, and give | ||
the user the option to join it. | ||
If no failure at this point the function hashes the password and inserts the data into a new db document | ||
in the teams collection. | ||
If the passed 'group' was empty we now return a status:1 with a successful registration message. If the 'joingroup' | ||
flag was set/true (and 'group' exists) we search for the group, if it does NOT exist we create it and add the new | ||
team as an owner and member. If it does exist we add the team as a member of the group. | ||
If 'joingroup' is not set/false but 'group' exists then we create the new group and add the user as an owner/member, | ||
we already know that the group does not exist (would have been caught at the beginning). | ||
""" | ||
email = request.form.get('email', '') | ||
teamname = request.form.get('team', '') | ||
adviser = request.form.get('name', '') | ||
affiliation = request.form.get('aff', '') | ||
pwd = request.form.get('pass', '') | ||
gname = request.form.get('group', '').lower().strip('') | ||
joingroup = request.form.get('joingroup', '') | ||
|
||
if '' in {email, teamname, adviser, affiliation, pwd}: | ||
return {'status': 0, 'message': "Please fill in all of the required fields."} | ||
if db.teams.find({'teamname': teamname}).count() != 0: | ||
return {'status': 0, 'message': "That team name is already registered."} | ||
if joingroup != 'true' and gname != '': | ||
if db.groups.find({'name': gname}).count() != 0: | ||
return {'status': 2, 'message': "The group name you have entered exists, would you like to join it?"} | ||
|
||
tid = common.token() | ||
db.teams.insert({'email': str(email), | ||
'advisor': str(adviser), | ||
'teamname': str(teamname), | ||
'affiliation': str(affiliation), | ||
'pwhash': bcrypt.hashpw(str(pwd), bcrypt.gensalt(8)), | ||
'tid': tid}) | ||
if gname == '': | ||
return {'status': 1, 'message': "Success! You have successfully registered."} | ||
|
||
if joingroup == 'true': | ||
if db.groups.find({'name': gname}).count() == 0: | ||
group.create_group(tid, gname) | ||
else: | ||
db.groups.update({'name': gname}, {'$push': {'members': tid}}) | ||
return {'status': 1, 'message': 'Success! You have been added to the group!'} | ||
else: | ||
group.create_group(tid, gname) | ||
return {'status': 1, 'message': "Success! You are registered and have created your group."} | ||
|
||
|
||
def update_password(tid, request): | ||
"""Update account password. | ||
Gets the new password and the password entered into the 'confirm password' box and verifies that 1) The new pw is | ||
not empty and 2) the new pw and the conf pw are the same. We salt/hash the password and update the team object | ||
in mongo then return a status:1 with a success message. | ||
""" | ||
pwd = request.form.get('pwd', '') | ||
conf = request.form.get('conf', '') | ||
if pwd == '': | ||
return {'status': 0, 'message': "The new password cannot be emtpy."} | ||
if pwd != conf: | ||
return {'status': 0, 'message': "The passwords do not match."} | ||
db.teams.update({'tid': tid}, {'$set': {'pwhash': bcrypt.hashpw(pwd, bcrypt.gensalt(8))}}) | ||
return {'status': 1, 'message': "Success! Your password has been updated."} | ||
|
||
|
||
def get_ssh_account(tid): | ||
"""Get a webshell account. | ||
Searches the sshaccts collection for a document that has the current team's tid, if one is found the creds are | ||
returned. If no ssh account is associated with the user an account with no tid is selected and assigned to the | ||
current team. The credentials are then returned. If no unused accounts are found an error email is sent to the | ||
admin_emails list and an error is returned. | ||
""" | ||
sshacct = db.sshaccts.find_one({'tid': tid}) | ||
if sshacct is not None: | ||
return {'username': sshacct['user'], 'password': sshacct['password']} | ||
sshacct = db.sshaccts.find_one({'$or': [{'tid': ''}, {'tid': {'$exists': False}}]}) | ||
if sshacct is not None: | ||
db.sshaccts.update({'_id': sshacct['_id']}, {'$set': {'tid': tid}}) | ||
return {'username': sshacct['user'], 'password': sshacct['password']} | ||
else: | ||
common.log('No free SSH accounts were found in the database.') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,271 @@ | ||
__author__ = ["Collin Petty", "Peter Chapman"] | ||
__copyright__ = "Carnegie Mellon University" | ||
__license__ = "MIT" | ||
__maintainer__ = ["Collin Petty", "Peter Chapman"] | ||
__credits__ = ["David Brumely", "Collin Petty", "Peter Chapman", "Tyler Nighswander", "Garrett Barboza"] | ||
__email__ = ["[email protected]", "[email protected]"] | ||
__status__ = "Production" | ||
|
||
|
||
import logging | ||
from flask import Flask, request, session, abort | ||
from functools import wraps | ||
|
||
import account | ||
import auth | ||
import common | ||
import group | ||
import problem | ||
import scoreboard | ||
import utilities | ||
import ConfigParser | ||
|
||
app = Flask("ctf") | ||
|
||
|
||
def require_login(f): | ||
@wraps(f) | ||
def wrapper(*args, **kwds): | ||
if 'tid' not in session: | ||
abort(403) | ||
return f(*args, **kwds) | ||
return wrapper | ||
|
||
|
||
def deny_blacklisted(f): | ||
@wraps(f) | ||
@require_login | ||
def wrapper(*args, **kwds): | ||
if auth.is_blacklisted(session['tid']): | ||
abort(403) | ||
return f(*args, **kwds) | ||
return wrapper | ||
|
||
|
||
def return_json(f): | ||
import json | ||
|
||
@wraps(f) | ||
def wrapper(*args, **kwds): | ||
return json.dumps(f(*args, **kwds)) | ||
return wrapper | ||
|
||
|
||
@app.before_first_request | ||
def setup_logging(): | ||
if not app.debug: | ||
app.logger.addHandler(logging.StreamHandler()) | ||
app.logger.setLevel(logging.INFO) | ||
|
||
|
||
@app.route('/api/login', methods=['POST']) | ||
@return_json | ||
def login_hook(): | ||
return auth.login(request, session) | ||
|
||
|
||
@app.route('/api/logout', methods=['GET']) | ||
@return_json | ||
def logout_hook(): | ||
return auth.logout(session) | ||
|
||
|
||
@app.route('/api/isloggedin', methods=['GET']) | ||
@return_json | ||
def is_logged_in_hook(): | ||
return auth.is_logged_in(session) | ||
|
||
|
||
@app.route('/api/register', methods=['POST']) | ||
@return_json | ||
def register_team_hook(): | ||
return account.register_team(request) | ||
|
||
|
||
@app.route('/api/updatepass', methods=['POST']) | ||
@return_json | ||
@require_login | ||
def update_password_hook(): | ||
return account.update_password(session['tid'], request) | ||
|
||
|
||
@app.route('/api/problems', methods=['GET']) | ||
@require_login | ||
@return_json | ||
def load_unlocked_problems_hook(): | ||
return problem.load_unlocked_problems(session['tid']) | ||
|
||
|
||
@app.route('/api/problems/solved', methods=['GET']) | ||
@require_login | ||
@return_json | ||
def get_solved_problems_hook(): | ||
return problem.get_solved_problems(session['tid']) | ||
|
||
|
||
@app.route('/api/problems/<path:pid>', methods=['GET']) | ||
@require_login | ||
@return_json | ||
def get_single_problem_hook(pid): | ||
problem_info = problem.get_single_problem(pid, session['tid']) | ||
if 'status' not in problem_info: | ||
problem_info.update({"status": 1}) | ||
return problem_info | ||
|
||
|
||
@app.route('/api/requestpasswordreset', methods=['POST']) | ||
@return_json | ||
def request_password_reset_hook(): | ||
return utilities.request_password_reset(request) | ||
|
||
|
||
@app.route('/api/resetpassword', methods=['POST']) | ||
@return_json | ||
def reset_password_hook(): | ||
return utilities.reset_password(request) | ||
|
||
|
||
@app.route('/api/lookupteamname', methods=['POST']) | ||
@return_json | ||
def lookup_team_names_hook(): | ||
return utilities.lookup_team_names(request.form.get('email', '')) | ||
|
||
|
||
@app.route('/api/creategroup', methods=['POST']) | ||
@require_login | ||
@return_json | ||
def create_group_hook(): | ||
return group.create_group(session['tid'], request.form.get('name', '')) | ||
|
||
|
||
@app.route('/api/joingroup', methods=['POST']) | ||
@require_login | ||
@return_json | ||
def join_group_hook(): | ||
gname = request.form.get('name', '') | ||
return group.join_group(session['tid'], gname) | ||
|
||
|
||
@app.route('/api/groups', methods=['GET']) | ||
@require_login | ||
@return_json | ||
def get_group_membership_hook(): | ||
return group.get_group_membership(session['tid']) | ||
|
||
|
||
@app.route('/api/leavegroup', methods=['POST']) | ||
@require_login | ||
@return_json | ||
def leave_group_hook(): | ||
gid = request.form.get('gid', '') | ||
return group.leave_group(session['tid'], gid) | ||
|
||
|
||
@app.route('/api/score', methods=['GET']) | ||
@require_login | ||
@return_json | ||
def load_team_score_hook(): | ||
return {'score': scoreboard.load_team_score(session['tid'])} | ||
|
||
|
||
@app.route('/api/scoreboards', methods=['GET']) | ||
@return_json | ||
def get_scoreboards_hook(): | ||
"""Loads the public scoreboard if the user is not logged in | ||
otherwise retrieves the group scoreboards as well""" | ||
scoreboards = [scoreboard.get_public_scoreboard()] | ||
if 'tid' in session: | ||
scoreboards += scoreboard.get_group_scoreboards(session['tid']) | ||
return scoreboards | ||
|
||
|
||
@app.route('/api/submit', methods=['POST']) | ||
@return_json | ||
@require_login | ||
def submit_problem_hook(): | ||
return problem.submit_problem(session['tid'], request) | ||
|
||
|
||
@app.route('/api/news', methods=['GET']) | ||
@return_json | ||
def load_news_hook(): | ||
return utilities.load_news() | ||
|
||
|
||
@app.route('/api/getsshacct', methods=['GET']) | ||
@return_json | ||
@require_login | ||
def get_ssh_account_hook(): | ||
return account.get_ssh_account(session['tid']) | ||
|
||
|
||
@app.after_request | ||
def after_request(response): | ||
if (request.headers.get('Origin', '') in | ||
['http://example.com', | ||
'http://www.example.com']): | ||
response.headers.add('Access-Control-Allow-Origin', | ||
request.headers['Origin']) | ||
response.headers.add('Access-Control-Allow-Methods', 'GET, POST') | ||
response.headers.add('Access-Control-Allow-Credentials', 'true') | ||
response.headers.add('Access-Control-Allow-Headers', 'Content-Type, *') | ||
response.headers.add('Cache-Control', 'no-cache') | ||
response.headers.add('Cache-Control', 'no-store') | ||
response.mimetype = 'application/json' | ||
return response | ||
|
||
|
||
def initialize(): | ||
common.log_level = ['ERROR', 'INFO'] | ||
config = ConfigParser.ConfigParser() | ||
config.read('mister.config') | ||
if config.get('debug', 'admin_emails') is not None: | ||
common.admin_emails = list() | ||
for email in config.get('debug', 'admin_emails').split(','): | ||
common.admin_emails.append(email.strip()) | ||
|
||
app.config['DEBUG'] = False | ||
secret_key = config.get('flask', 'secret_key').decode('hex') | ||
if secret_key == '': | ||
common.log('The Flask secret key specified in the config file is empty.') | ||
exit() | ||
app.secret_key = secret_key | ||
app.config['SESSION_COOKIE_HTTPONLY'] = False | ||
app.config['SESSION_COOKIE_DOMAIN'] = config.get('flask', 'SESSION_COOKIE_DOMAIN') | ||
app.config['SESSION_COOKIE_PATH'] = config.get('flask', 'SESSION_COOKIE_PATH') | ||
app.config['SESSION_COOKIE_NAME'] = config.get('flask', 'SESSION_COOKIE_NAME') | ||
|
||
enable_email = config.get('email', 'enable_email') | ||
if enable_email: | ||
common.log('Enabling Email support.', 'INFO') | ||
utilities.enable_email = enable_email | ||
smtp_url = config.get('email', 'smtp_url') | ||
common.log("SMTP Server set to '%s'" % smtp_url, 'INFO') | ||
utilities.smtp_url = smtp_url | ||
|
||
email_username = config.get('email', 'username') | ||
common.log("SMTP username set to '%s'" % email_username, 'INFO') | ||
utilities.email_username = email_username | ||
|
||
email_password = config.get('email', 'password') | ||
common.log("SMTP password set to '%s'" % ('*' * len(email_password)), 'INFO') | ||
utilities.email_password = email_password | ||
|
||
from_addr = config.get('email', 'from_addr') | ||
common.log("Email from addr set to '%s'" % from_addr, 'INFO') | ||
utilities.from_addr = from_addr | ||
|
||
from_name = config.get('email', 'from_name') | ||
common.log("Setting sender name to '%s'" % from_name, 'INFO') | ||
utilities.from_name = from_name | ||
|
||
problem.root_web_path = config.get('autogen', 'root_web_path') | ||
problem.relative_auto_prob_path = config.get('autogen', 'relative_auto_prob_path') | ||
common.log_level = ['ERROR'] | ||
|
||
|
||
initialize() # load all config settings and configure flask keys | ||
problem.load_autogenerators() # load all auto-generated problems | ||
|
||
if __name__ == "__main__": | ||
app.run(host="0.0.0.0", port=8000) |
Oops, something went wrong.