Skip to content

Commit

Permalink
Initial release of the CTF Platform based on picoCTF 2013
Browse files Browse the repository at this point in the history
  • Loading branch information
collinpetty authored and collinpetty committed Aug 26, 2013
1 parent f11a492 commit 8402f3d
Show file tree
Hide file tree
Showing 355 changed files with 29,030 additions and 0 deletions.
103 changes: 103 additions & 0 deletions api/account.py
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.')
271 changes: 271 additions & 0 deletions api/api.py
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)
Loading

0 comments on commit 8402f3d

Please sign in to comment.