Exemple #1
0
def admin_pages(route):
    if request.method == 'GET' and request.args.get('mode') == 'create':
        return render_template('admin/editor.html')
    if route and request.method == 'GET':
        page = Pages.query.filter_by(route=route).first()
        return render_template('admin/editor.html', page=page)
    if route and request.method == 'POST':
        page = Pages.query.filter_by(route=route).first()
        errors = []
        html = request.form['html']
        route = request.form['route']
        if not route:
            errors.append('Missing URL route')
        if errors:
            page = Pages(html, "")
            return render_template('/admin/editor.html', page=page)
        if page:
            page.route = route
            page.html = html
            db.session.commit()
            return redirect(url_for('admin.admin_pages'))
        page = Pages(route, html)
        db.session.add(page)
        db.session.commit()
        return redirect(url_for('admin.admin_pages'))
    pages = Pages.query.all()
    return render_template('admin/pages.html', routes=pages, css=get_config('css'))
Exemple #2
0
def setup():
    # with app.app_context():
        # admin = Teams.query.filter_by(admin=True).first()

    if not utils.is_setup():
        if not session.get('nonce'):
            session['nonce'] = utils.sha512(os.urandom(10))
        if request.method == 'POST':
            ctf_name = request.form['ctf_name']
            ctf_name = utils.set_config('ctf_name', ctf_name)

            # CSS
            css = utils.set_config('start', '')

            # Admin user
            name = request.form['name']
            email = request.form['email']
            password = request.form['password']
            admin = Teams(name, email, password)
            admin.admin = True
            admin.banned = True

            # Index page
            page = Pages('index', """<div class="container main-container">
    <img class="logo" src="themes/treehacks/static/img/logo.png" />
    <h3 class="text-center">
        <p>A cool CTF platform from <a href="https://ctfd.io">ctfd.io</a></p>
        <p>Follow us on social media:</p>
        <a href="https://twitter.com/ctfdio"><i class="fa fa-twitter fa-2x" aria-hidden="true"></i></a>&nbsp;
        <a href="https://facebook.com/ctfdio"><i class="fa fa-facebook-official fa-2x" aria-hidden="true"></i></a>&nbsp;
        <a href="https://github.com/ctfd"><i class="fa fa-github fa-2x" aria-hidden="true"></i></a>
    </h3>
    <br>
    <h4 class="text-center">
        <a href="admin">Click here</a> to login and setup your CTF
    </h4>
</div>""".format(request.script_root))

            # max attempts per challenge
            max_tries = utils.set_config('max_tries', 0)

            # Start time
            start = utils.set_config('start', None)
            end = utils.set_config('end', None)
            freeze = utils.set_config('freeze', None)

            # Challenges cannot be viewed by unregistered users
            view_challenges_unregistered = utils.set_config('view_challenges_unregistered', None)

            # Allow/Disallow registration
            prevent_registration = utils.set_config('prevent_registration', None)

            # Verify emails
            verify_emails = utils.set_config('verify_emails', None)

            mail_server = utils.set_config('mail_server', None)
            mail_port = utils.set_config('mail_port', None)
            mail_tls = utils.set_config('mail_tls', None)
            mail_ssl = utils.set_config('mail_ssl', None)
            mail_username = utils.set_config('mail_username', None)
            mail_password = utils.set_config('mail_password', None)
            mail_useauth = utils.set_config('mail_useauth', None)

            setup = utils.set_config('setup', True)

            db.session.add(page)
            db.session.add(admin)
            db.session.commit()

            session['username'] = admin.name
            session['id'] = admin.id
            session['admin'] = admin.admin
            session['nonce'] = utils.sha512(os.urandom(10))

            db.session.close()
            app.setup = False
            with app.app_context():
                cache.clear()

            return redirect(url_for('views.static_html'))
        return render_template('setup.html', nonce=session.get('nonce'))
    return redirect(url_for('views.static_html'))
Exemple #3
0
def setup():
    # with app.app_context():
    # admin = Teams.query.filter_by(admin=True).first()

    if not utils.is_setup():
        if not session.get('nonce'):
            session['nonce'] = utils.sha512(os.urandom(10))
        if request.method == 'POST':
            ctf_name = request.form['ctf_name']
            ctf_name = utils.set_config('ctf_name', ctf_name)

            # CSS
            css = utils.set_config('start', '')

            # Admin user
            name = request.form['name']
            email = request.form['email']
            password = request.form['password']
            admin = Teams(name, email, password)
            admin.admin = True
            admin.banned = True

            # Index page
            page = Pages(
                'index', """<div class="container main-container">
    <img class="logo" src="{0}/static/original/img/logo.png" />
    <h3 class="text-center">
        Welcome to a cool CTF framework written by <a href="https://github.com/ColdHeat">Kevin Chung</a> of <a href="https://github.com/isislab">@isislab</a>
    </h3>

    <h4 class="text-center">
        <a href="{0}/admin">Click here</a> to login and setup your CTF
    </h4>
</div>""".format(request.script_root))

            # max attempts per challenge
            max_tries = utils.set_config('max_tries', 0)

            # Start time
            start = utils.set_config('start', None)
            end = utils.set_config('end', None)
            freeze = utils.set_config('freeze', None)

            # Challenges cannot be viewed by unregistered users
            view_challenges_unregistered = utils.set_config(
                'view_challenges_unregistered', None)

            # Allow/Disallow registration
            prevent_registration = utils.set_config('prevent_registration',
                                                    None)

            # Verify emails
            verify_emails = utils.set_config('verify_emails', None)

            mail_server = utils.set_config('mail_server', None)
            mail_port = utils.set_config('mail_port', None)
            mail_tls = utils.set_config('mail_tls', None)
            mail_ssl = utils.set_config('mail_ssl', None)
            mail_username = utils.set_config('mail_username', None)
            mail_password = utils.set_config('mail_password', None)

            setup = utils.set_config('setup', True)

            db.session.add(page)
            db.session.add(admin)
            db.session.commit()

            session['username'] = admin.name
            session['id'] = admin.id
            session['admin'] = admin.admin
            session['nonce'] = utils.sha512(os.urandom(10))

            db.session.close()
            app.setup = False
            with app.app_context():
                cache.clear()

            return redirect(url_for('views.static_html'))
        return render_template('setup.html', nonce=session.get('nonce'))
    return redirect(url_for('views.static_html'))
Exemple #4
0
def import_ctf(backup, segments=None, erase=False):
    side_db = dataset.connect(get_config('SQLALCHEMY_DATABASE_URI'))
    if segments is None:
        segments = ['challenges', 'teams', 'both', 'metadata']

    if not zipfile.is_zipfile(backup):
        raise TypeError

    backup = zipfile.ZipFile(backup)

    groups = {
        'challenges': [
            'challenges',
            'files',
            'tags',
            'keys',
            'hints',
        ],
        'teams': [
            'teams',
            'tracking',
            'awards',
        ],
        'both': [
            'solves',
            'wrong_keys',
            'unlocks',
        ],
        'metadata': [
            'alembic_version',
            'config',
            'pages',
            'containers',
        ]
    }

    # Need special handling of metadata
    if 'metadata' in segments:
        meta = groups['metadata']
        segments.remove('metadata')
        meta.remove('alembic_version')

        for item in meta:
            table = side_db[item]
            path = "db/{}.json".format(item)
            data = backup.open(path).read()

            # Some JSON files will be empty
            if data:
                if item == 'config':
                    saved = json.loads(data)
                    for entry in saved['results']:
                        key = entry['key']
                        value = entry['value']
                        set_config(key, value)

                elif item == 'pages':
                    saved = json.loads(data)
                    for entry in saved['results']:
                        route = entry['route']
                        html = entry['html']
                        page = Pages.query.filter_by(route=route).first()
                        if page:
                            page.html = html
                        else:
                            page = Pages(route, html)
                            db.session.add(page)
                        db.session.commit()

                elif item == 'containers':
                    saved = json.loads(data)
                    for entry in saved['results']:
                        name = entry['name']
                        buildfile = entry['buildfile']
                        container = Containers.query.filter_by(name=name).first()
                        if container:
                            container.buildfile = buildfile
                        else:
                            container = Containers(name, buildfile)
                            db.session.add(container)
                        db.session.commit()

    for segment in segments:
        group = groups[segment]
        for item in group:
            table = side_db[item]
            path = "db/{}.json".format(item)
            data = backup.open(path).read()
            if data:
                saved = json.loads(data)
                for entry in saved['results']:
                    entry_id = entry.pop('id', None)
                    table.insert(entry)
            else:
                continue

    # Extracting files
    files = [f for f in backup.namelist() if f.startswith('uploads/')]
    upload_folder = app.config.get('UPLOAD_FOLDER')
    for f in files:
        filename = f.split(os.sep, 1)

        if len(filename) < 2:  # just an empty uploads directory (e.g. uploads/)
            continue

        filename = filename[1]  # Get the second entry in the list (the actual filename)
        full_path = os.path.join(upload_folder, filename)
        dirname = os.path.dirname(full_path)

        # Create any parent directories for the file
        if not os.path.exists(dirname):
            os.makedirs(dirname)

        source = backup.open(f)
        target = file(full_path, "wb")
        with source, target:
            shutil.copyfileobj(source, target)
Exemple #5
0
def import_ctf(backup, segments=None, erase=False):
    side_db = dataset.connect(get_app_config('SQLALCHEMY_DATABASE_URI'))
    if segments is None:
        segments = ['challenges', 'teams', 'both', 'metadata']

    if not zipfile.is_zipfile(backup):
        raise TypeError

    backup = zipfile.ZipFile(backup)

    groups = {
        'challenges': [
            'challenges',
            'files',
            'tags',
            'keys',
            'hints',
        ],
        'teams': [
            'teams',
            'tracking',
            'awards',
        ],
        'both': [
            'solves',
            'wrong_keys',
            'unlocks',
        ],
        'metadata': [
            'alembic_version',
            'config',
            'pages',
        ]
    }

    # Need special handling of metadata
    if 'metadata' in segments:
        meta = groups['metadata']
        segments.remove('metadata')
        meta.remove('alembic_version')

        for item in meta:
            table = side_db[item]
            path = "db/{}.json".format(item)
            data = backup.open(path).read()

            # Some JSON files will be empty
            if data:
                if item == 'config':
                    saved = json.loads(data)
                    for entry in saved['results']:
                        key = entry['key']
                        value = entry['value']
                        set_config(key, value)

                elif item == 'pages':
                    saved = json.loads(data)
                    for entry in saved['results']:
                        # Support migration c12d2a1b0926_add_draft_and_title_to_pages
                        route = entry['route']
                        title = entry.get('title', route.title())
                        html = entry['html']
                        draft = entry.get('draft', False)
                        auth_required = entry.get('auth_required', False)
                        page = Pages.query.filter_by(route=route).first()
                        if page:
                            page.html = html
                        else:
                            page = Pages(title,
                                         route,
                                         html,
                                         draft=draft,
                                         auth_required=auth_required)
                            db.session.add(page)
                        db.session.commit()

    teams_base = db.session.query(db.func.max(Teams.id)).scalar() or 0
    chals_base = db.session.query(db.func.max(Challenges.id)).scalar() or 0

    for segment in segments:
        group = groups[segment]
        for item in group:
            table = side_db[item]
            path = "db/{}.json".format(item)
            data = backup.open(path).read()
            if data:
                saved = json.loads(data)
                for entry in saved['results']:
                    entry_id = entry.pop('id', None)
                    # This is a hack to get SQlite to properly accept datetime values from dataset
                    # See Issue #246
                    if get_app_config('SQLALCHEMY_DATABASE_URI').startswith(
                            'sqlite'):
                        for k, v in entry.items():
                            if isinstance(v, six.string_types):
                                match = re.match(
                                    r"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d",
                                    v)
                                if match:
                                    entry[k] = datetime.datetime.strptime(
                                        v, '%Y-%m-%dT%H:%M:%S.%f')
                                    continue
                                match = re.match(
                                    r"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}", v)
                                if match:
                                    entry[k] = datetime.datetime.strptime(
                                        v, '%Y-%m-%dT%H:%M:%S')
                                    continue
                    for k, v in entry.items():
                        if k == 'chal' or k == 'chalid':
                            entry[k] += chals_base
                        if k == 'team' or k == 'teamid':
                            entry[k] += teams_base

                    if item == 'teams':
                        table.insert_ignore(entry, ['email'])
                    elif item == 'keys':
                        # Support migration 2539d8b5082e_rename_key_type_to_type
                        key_type = entry.get('key_type', None)
                        if key_type is not None:
                            entry['type'] = key_type
                            del entry['key_type']
                        table.insert(entry)
                    else:
                        table.insert(entry)
            else:
                continue

    # Extracting files
    files = [f for f in backup.namelist() if f.startswith('uploads/')]
    upload_folder = app.config.get('UPLOAD_FOLDER')
    for f in files:
        filename = f.split(os.sep, 1)

        if len(filename
               ) < 2:  # just an empty uploads directory (e.g. uploads/)
            continue

        filename = filename[
            1]  # Get the second entry in the list (the actual filename)
        full_path = os.path.join(upload_folder, filename)
        dirname = os.path.dirname(full_path)

        # Create any parent directories for the file
        if not os.path.exists(dirname):
            os.makedirs(dirname)

        source = backup.open(f)
        target = open(full_path, "wb")
        with source, target:
            shutil.copyfileobj(source, target)
Exemple #6
0
def setup():
    # with app.app_context():
    # admin = Teams.query.filter_by(admin=True).first()

    if not utils.is_setup():
        if not session.get('nonce'):
            session['nonce'] = utils.sha512(os.urandom(10))
        if request.method == 'POST':
            ctf_name = request.form['ctf_name']
            ctf_name = utils.set_config('ctf_name', ctf_name)

            # CSS
            css = utils.set_config('start', '')

            # Admin user
            name = request.form['name']
            email = request.form['email']
            password = request.form['password']
            admin = Teams(name, email, password)
            admin.admin = True
            admin.banned = True

            # Index page

            index = """<div class="row">
  <style>
   .col-container:after { content: ""; display: table; clear: both; }
   .col { float: left; }
   .clearfix::after {
  content: "";
  display: table;
  clear: both;
    }
    .footer-nav{
      float: left;
    }
    .logo{
      float: right;
    }
    .footer-nav,
    .footer-nav li{
      display: inline;
    }
  </style>
  <div class="col-md-6 offset-md-3">
<h1 class="text-center" style="padding-top: 10vh; font-size: 50px;">
    <b>Haaukins</b>
</h1>
<p class="text-center">
    A platform for Cyber Security Exercises 
</p>
<p class="text-center">
    Founded by <a href="http://danishcybersecurityclusters.dk/">Danish Cyber Security Clusters</a> and supported by
</p>
<a href="https://www.industriensfond.dk/">
    <img class="w-100 mx-auto d-block" style="max-width: 300px; padding: 3vh 0 4vh 0;" src="/themes/core/static/img/logo_industrienfond.jpg">
</a>
<p class="text-center">
    <p class="text-center">
  Developed at <a href="http://es.aau.dk/">Aalborg University</a> (Department of Electronic Systems) by:
    </p>
    <div class="col-container" style="margin-top: 40px;">
  <div class="col" style="width: 40%">
          <img src="/themes/core/static/img/haaukins_logo_blue240px.png" style="margin-left: 20px; max-width: 170px;">
    </div>
  <div class="col" style="width: 60%; font-size:14px;">
      <p><a href="https://mrturkmen.com">Ahmet Turkmen</a> (Research Assistant)</p>
      <p><a href="https://github.com/eyJhb">Gian Marco Mennecozzi</a> (Research Assistant)</p>
      <p><a href="https://github.com/kdhageman">Kaspar Hageman</a> (Ph.D. Student)</p>
      <p><a href="https://github.com/tpanum">Thomas Kobber Panum</a> (Ph.D. Student)</p>
      <p><a href="https://github.com/eyJhb">Johan Hempel Bengtson</a> (Student Helper)</p>
    </div>
    </div>
</p>
<div class="card-deck py-4">
      <div class="card">
          <div class="card-body">
              <h5 class="card-title">Tips and tricks</h5>
              <div class="card-text">
                  Stuck at a certain challenge? Or do you just want to know more about a certain topic?
              </div>
          </div>
          <div class="card-footer">
              <a href="https://aau-network-security.github.io/tips-and-tricks/" target="_blank">Vist the tips & tricks page</a>
          </div>
      </div>
      <div class="card">
          <div class="card-body">
              <h5 class="card-title">Survey</h5>
              <p>You can help us improve the platform by taking our survey to let us know about your experiences!</p>
          </div>
          <div class="card-footer">
              <a href="https://www.survey-xact.dk/LinkCollector?key=KDRVSTDJJN15" target="_blank">Fill out the survey here</a>
          </div>
      </div>
  </div>
<p class="text-center">
    Feel free to join our local Facebook Group:
</p>
<p class="text-center">
    <a href="https://www.facebook.com/groups/957517617737780"><i class="fab fa-facebook" aria-hidden="true"></i>&nbsp;AAU Hackers &amp; Friends</a>
</p>
  <div class="container">
      <footer>
          <ul class="footer-nav">
              <li><a href="https://eadania.dk/"> <img src="/themes/core/static/img/da-90.png" style= "width:90px; height:75px;" ></a></li>
              <li><a href="https://www.dtu.dk/"><img src="/themes/core/static/img/dtu-90.png" style= "width:90px; height:75px;"></a></li>
              <li><a href="https://kea.dk/"> <img src="/themes/core/static/img/kea-90.jpg" style= "width:90px; height:75px;" ></a></li>
              <li><a href="https://happy42.dk/"> <img src="/themes/core/static/img/happy-90.png" style= "width:90px; height:75px;" ></a></li>
               <li><a href="https://www.eaaa.dk/"><img src="/themes/core/static/img/eaa-90.png" style= "width:90px; height:75px;"></a></li>
         </ul>
      </footer>
      </div>
  </div>    
</div>"""

            page = Pages(title=None, route='index', html=index, draft=False)

            # max attempts per challenge
            max_tries = utils.set_config('max_tries', 0)

            # Start time
            start = utils.set_config('start', None)
            end = utils.set_config('end', None)
            freeze = utils.set_config('freeze', None)

            # Challenges cannot be viewed by unregistered users
            view_challenges_unregistered = utils.set_config(
                'view_challenges_unregistered', None)

            # Allow/Disallow registration
            prevent_registration = utils.set_config('prevent_registration',
                                                    None)

            # Verify emails
            verify_emails = utils.set_config('verify_emails', None)

            mail_server = utils.set_config('mail_server', None)
            mail_port = utils.set_config('mail_port', None)
            mail_tls = utils.set_config('mail_tls', None)
            mail_ssl = utils.set_config('mail_ssl', None)
            mail_username = utils.set_config('mail_username', None)
            mail_password = utils.set_config('mail_password', None)
            mail_useauth = utils.set_config('mail_useauth', None)

            setup = utils.set_config('setup', True)

            db.session.add(page)
            db.session.add(admin)
            db.session.commit()

            session['username'] = admin.name
            session['id'] = admin.id
            session['admin'] = admin.admin
            session['nonce'] = utils.sha512(os.urandom(10))

            db.session.close()
            app.setup = False
            with app.app_context():
                cache.clear()

            return redirect(url_for('views.static_html'))
        return render_template('setup.html', nonce=session.get('nonce'))
    return redirect(url_for('views.static_html'))
Exemple #7
0
def setup():
    # with app.app_context():
    # admin = Teams.query.filter_by(admin=True).first()

    if not is_setup():
        if not session.get('nonce'):
            session['nonce'] = sha512(os.urandom(10))
        if request.method == 'POST':
            ctf_name = request.form['ctf_name']
            ctf_name = set_config('ctf_name', ctf_name)

            ## CSS
            css = set_config('start', '')

            ## Admin user
            name = request.form['name']
            email = request.form['email']
            password = request.form['password']
            admin = Teams(name, email, password)
            admin.admin = True
            admin.banned = True

            ## Index page
            page = Pages(
                'index', """<div class="container main-container">
    <img class="logo" src="{0}/static/original/img/logo.jpg" />
    <h3 class="text-center">
        Welcome to pogTeam's recruiting CTF! Keep in touch through our IRC chan ##pogTeam (freenode) or our <a href="https://t.me/pogTeamPublico">Telegram chan</a>!
    </h3>

    <h4 class="text-center">
        <a href="{0}/admin">Click here</a> to login and setup your CTF
    </h4>
</div>""".format(request.script_root))

            #max attempts per challenge
            max_tries = set_config("max_tries", 0)

            ## Start time
            start = set_config('start', None)
            end = set_config('end', None)

            ## Challenges cannot be viewed by unregistered users
            view_challenges_unregistered = set_config(
                'view_challenges_unregistered', None)

            ## Allow/Disallow registration
            prevent_registration = set_config('prevent_registration', None)

            ## Verify emails
            verify_emails = set_config('verify_emails', None)

            mail_server = set_config('mail_server', None)
            mail_port = set_config('mail_port', None)
            mail_tls = set_config('mail_tls', None)
            mail_ssl = set_config('mail_ssl', None)
            mail_username = set_config('mail_username', None)
            mail_password = set_config('mail_password', None)

            setup = set_config('setup', True)

            db.session.add(page)
            db.session.add(admin)
            db.session.commit()
            db.session.close()
            app.setup = False
            with app.app_context():
                cache.clear()
            return redirect(url_for('views.static_html'))
        return render_template('setup.html', nonce=session.get('nonce'))
    return redirect(url_for('views.static_html'))
Exemple #8
0
def setup():
    if not config.is_setup():
        if not session.get('nonce'):
            session['nonce'] = generate_nonce()
        if request.method == 'POST':
            ctf_name = request.form['ctf_name']
            set_config('ctf_name', ctf_name)

            # CSS
            set_config('start', '')

            # Admin user
            name = request.form['name']
            email = request.form['email']
            password = request.form['password']
            admin = Admins(name=name,
                           email=email,
                           password=password,
                           type='admin',
                           hidden=True)

            user_mode = request.form['user_mode']

            set_config('user_mode', user_mode)

            # Index page

            index = """<div class="row">
    <div class="col-md-6 offset-md-3">
        <img class="w-100 mx-auto d-block" style="max-width: 500px;padding: 50px;padding-top: 14vh;" src="themes/core/static/img/uioctf_logo.png" />
        <h3 class="text-center">
            <p>A cool CTF platform from <a href="https://ctfd.io">ctfd.io</a></p>
            <p>Follow us on social media:</p>
            <a href="https://twitter.com/ctfdio"><i class="fab fa-twitter fa-2x" aria-hidden="true"></i></a>&nbsp;
            <a href="https://facebook.com/ctfdio"><i class="fab fa-facebook fa-2x" aria-hidden="true"></i></a>&nbsp;
            <a href="https://github.com/ctfd"><i class="fab fa-github fa-2x" aria-hidden="true"></i></a>
        </h3>
        <br>
        <h4 class="text-center">
            <a href="admin">Click here</a> to login and setup your CTF
        </h4>
    </div>
</div>""".format(request.script_root)

            page = Pages(title=None, route='index', content=index, draft=False)
            # Visibility
            set_config('challenge_visibility', 'private')
            set_config('registration_visibility', 'public')
            set_config('score_visibility', 'public')
            set_config('account_visibility', 'public')

            # Start time
            set_config('start', None)
            set_config('end', None)
            set_config('freeze', None)

            # Verify emails
            set_config('verify_emails', None)

            set_config('mail_server', None)
            set_config('mail_port', None)
            set_config('mail_tls', None)
            set_config('mail_ssl', None)
            set_config('mail_username', None)
            set_config('mail_password', None)
            set_config('mail_useauth', None)

            setup = set_config('setup', True)

            try:
                db.session.add(admin)
                db.session.commit()
            except IntegrityError:
                db.session.rollback()

            try:
                db.session.add(page)
                db.session.commit()
            except IntegrityError:
                db.session.rollback()

            login_user(admin)

            db.session.close()
            app.setup = False
            with app.app_context():
                cache.clear()

            return redirect(url_for('views.static_html'))
        return render_template('setup.html', nonce=session.get('nonce'))
    return redirect(url_for('views.static_html'))
Exemple #9
0
def setup():
    errors = get_errors()
    if not config.is_setup():
        if not session.get("nonce"):
            session["nonce"] = generate_nonce()
        if request.method == "POST":
            # General
            ctf_name = request.form.get("ctf_name")
            ctf_description = request.form.get("ctf_description")
            user_mode = request.form.get("user_mode", USERS_MODE)
            set_config("ctf_name", ctf_name)
            set_config("ctf_description", ctf_description)
            set_config("user_mode", user_mode)

            # Style
            ctf_logo = request.files.get("ctf_logo")
            if ctf_logo:
                f = upload_file(file=ctf_logo)
                set_config("ctf_logo", f.location)

            ctf_small_icon = request.files.get("ctf_small_icon")
            if ctf_small_icon:
                f = upload_file(file=ctf_small_icon)
                set_config("ctf_small_icon", f.location)

            theme = request.form.get("ctf_theme", DEFAULT_THEME)
            set_config("ctf_theme", theme)
            theme_color = request.form.get("theme_color")
            theme_header = get_config("theme_header")
            if theme_color and bool(theme_header) is False:
                # Uses {{ and }} to insert curly braces while using the format method
                css = (
                    '<style id="theme-color">\n'
                    ":root {{--theme-color: {theme_color};}}\n"
                    ".navbar{{background-color: var(--theme-color) !important;}}\n"
                    ".jumbotron{{background-color: var(--theme-color) !important;}}\n"
                    "</style>\n"
                ).format(theme_color=theme_color)
                set_config("theme_header", css)

            # DateTime
            start = request.form.get("start")
            end = request.form.get("end")
            set_config("start", start)
            set_config("end", end)
            set_config("freeze", None)

            # Administration
            name = request.form["name"]
            email = request.form["email"]
            password = request.form["password"]

            name_len = len(name) == 0
            names = Users.query.add_columns("name", "id").filter_by(name=name).first()
            emails = (
                Users.query.add_columns("email", "id").filter_by(email=email).first()
            )
            pass_short = len(password) == 0
            pass_long = len(password) > 128
            valid_email = validators.validate_email(request.form["email"])
            team_name_email_check = validators.validate_email(name)

            if not valid_email:
                errors.append("Please enter a valid email address")
            if names:
                errors.append("That user name is already taken")
            if team_name_email_check is True:
                errors.append("Your user name cannot be an email address")
            if emails:
                errors.append("That email has already been used")
            if pass_short:
                errors.append("Pick a longer password")
            if pass_long:
                errors.append("Pick a shorter password")
            if name_len:
                errors.append("Pick a longer user name")

            if len(errors) > 0:
                return render_template(
                    "setup.html",
                    errors=errors,
                    name=name,
                    email=email,
                    password=password,
                    state=serialize(generate_nonce()),
                )

            admin = Admins(
                name=name, email=email, password=password, type="admin", hidden=True
            )

            # Create an empty index page
            page = Pages(title=None, route="index", content="", draft=False)

            # Upload banner
            default_ctf_banner_location = url_for("views.themes", path="img/logo.png")
            ctf_banner = request.files.get("ctf_banner")
            if ctf_banner:
                f = upload_file(file=ctf_banner, page_id=page.id)
                default_ctf_banner_location = url_for("views.files", path=f.location)

            # Splice in our banner
            index = f"""<div class="row">
    <div class="col-md-6 offset-md-3">
        <img class="w-100 mx-auto d-block" style="max-width: 500px;padding: 50px;padding-top: 14vh;" src="{default_ctf_banner_location}" />
        <h3 class="text-center">
            <p>A cool CTF platform from <a href="https://ctfd.io">ctfd.io</a></p>
            <p>Follow us on social media:</p>
            <a href="https://twitter.com/ctfdio"><i class="fab fa-twitter fa-2x" aria-hidden="true"></i></a>&nbsp;
            <a href="https://facebook.com/ctfdio"><i class="fab fa-facebook fa-2x" aria-hidden="true"></i></a>&nbsp;
            <a href="https://github.com/ctfd"><i class="fab fa-github fa-2x" aria-hidden="true"></i></a>
        </h3>
        <br>
        <h4 class="text-center">
            <a href="admin">Click here</a> to login and setup your CTF
        </h4>
    </div>
</div>"""
            page.content = index

            # Visibility
            set_config(
                ConfigTypes.CHALLENGE_VISIBILITY, ChallengeVisibilityTypes.PRIVATE
            )
            set_config(
                ConfigTypes.REGISTRATION_VISIBILITY, RegistrationVisibilityTypes.PUBLIC
            )
            set_config(ConfigTypes.SCORE_VISIBILITY, ScoreVisibilityTypes.PUBLIC)
            set_config(ConfigTypes.ACCOUNT_VISIBILITY, AccountVisibilityTypes.PUBLIC)

            # Verify emails
            set_config("verify_emails", None)

            set_config("mail_server", None)
            set_config("mail_port", None)
            set_config("mail_tls", None)
            set_config("mail_ssl", None)
            set_config("mail_username", None)
            set_config("mail_password", None)
            set_config("mail_useauth", None)

            # Set up default emails
            set_config("verification_email_subject", DEFAULT_VERIFICATION_EMAIL_SUBJECT)
            set_config("verification_email_body", DEFAULT_VERIFICATION_EMAIL_BODY)

            set_config(
                "successful_registration_email_subject",
                DEFAULT_SUCCESSFUL_REGISTRATION_EMAIL_SUBJECT,
            )
            set_config(
                "successful_registration_email_body",
                DEFAULT_SUCCESSFUL_REGISTRATION_EMAIL_BODY,
            )

            set_config(
                "user_creation_email_subject", DEFAULT_USER_CREATION_EMAIL_SUBJECT
            )
            set_config("user_creation_email_body", DEFAULT_USER_CREATION_EMAIL_BODY)

            set_config("password_reset_subject", DEFAULT_PASSWORD_RESET_SUBJECT)
            set_config("password_reset_body", DEFAULT_PASSWORD_RESET_BODY)

            set_config(
                "password_change_alert_subject",
                "Password Change Confirmation for {ctf_name}",
            )
            set_config(
                "password_change_alert_body",
                (
                    "Your password for {ctf_name} has been changed.\n\n"
                    "If you didn't request a password change you can reset your password here: {url}"
                ),
            )

            set_config("setup", True)

            try:
                db.session.add(admin)
                db.session.commit()
            except IntegrityError:
                db.session.rollback()

            try:
                db.session.add(page)
                db.session.commit()
            except IntegrityError:
                db.session.rollback()

            login_user(admin)

            db.session.close()
            with app.app_context():
                cache.clear()

            return redirect(url_for("views.static_html"))
        try:
            return render_template("setup.html", state=serialize(generate_nonce()))
        except TemplateNotFound:
            # Set theme to default and try again
            set_config("ctf_theme", DEFAULT_THEME)
            return render_template("setup.html", state=serialize(generate_nonce()))
    return redirect(url_for("views.static_html"))
Exemple #10
0
def setup():
    # with app.app_context():
    # admin = Teams.query.filter_by(admin=True).first()

    if not utils.is_setup():
        if not session.get('nonce'):
            session['nonce'] = utils.sha512(os.urandom(10))
        if request.method == 'POST':
            ctf_name = request.form['ctf_name']
            ctf_name = utils.set_config('ctf_name', ctf_name)

            # CSS
            css = utils.set_config('start', '')

            # Admin user
            name = request.form['name']
            email = request.form['email']
            password = request.form['password']
            admin = Teams(name, email, password)
            admin.admin = True
            admin.banned = True

            # Index page

            index = """<div class="row">
                <div class="intro">
                    <img width=30 src="themes/arg/static/img/logo.png" />
                    <br>
                    <br>
                    <p>
                        the console will set you free
                    </p>
                    <script>
                        console_message('ef98fe223e630bbb82dd9c41323e3290')
                    </script>
                    <br>
                </div>
            </div>""".format(request.script_root)

            page = Pages(title=None, route='index', html=index, draft=False)

            # max attempts per challenge
            max_tries = utils.set_config('max_tries', 0)

            # Start time
            start = utils.set_config('start', None)
            end = utils.set_config('end', None)
            freeze = utils.set_config('freeze', None)

            # Challenges cannot be viewed by unregistered users
            view_challenges_unregistered = utils.set_config(
                'view_challenges_unregistered', None)

            # Allow/Disallow registration
            prevent_registration = utils.set_config('prevent_registration',
                                                    None)

            # Verify emails
            verify_emails = utils.set_config('verify_emails', None)

            mail_server = utils.set_config('mail_server', None)
            mail_port = utils.set_config('mail_port', None)
            mail_tls = utils.set_config('mail_tls', None)
            mail_ssl = utils.set_config('mail_ssl', None)
            mail_username = utils.set_config('mail_username', None)
            mail_password = utils.set_config('mail_password', None)
            mail_useauth = utils.set_config('mail_useauth', None)

            setup = utils.set_config('setup', True)

            db.session.add(page)
            db.session.add(admin)
            db.session.commit()

            session['username'] = admin.name
            session['id'] = admin.id
            session['admin'] = admin.admin
            session['nonce'] = utils.sha512(os.urandom(10))

            db.session.close()
            app.setup = False
            with app.app_context():
                cache.clear()

            return redirect(url_for('views.static_html'))
        return render_template('setup.html', nonce=session.get('nonce'))
    return redirect(url_for('views.static_html'))
Exemple #11
0
def admin_pages_view():
    page_id = request.args.get('id')
    page_op = request.args.get('operation')

    if request.method == 'GET' and page_op == 'preview':
        page = Pages.query.filter_by(id=page_id).first_or_404()
        return render_template('page.html', content=markdown(page.html))

    if request.method == 'GET' and page_op == 'create':
        return render_template('admin/editor.html')

    if page_id and request.method == 'GET':
        page = Pages.query.filter_by(id=page_id).first()
        return render_template('admin/editor.html', page=page)

    if request.method == 'POST':
        page_form_id = request.form.get('id')
        title = request.form['title']
        html = request.form['html']
        route = request.form['route'].lstrip('/')
        auth_required = 'auth_required' in request.form

        if page_op == 'preview':
            page = Pages(title, route, html, draft=False)
            return render_template('page.html', content=markdown(page.html))

        page = Pages.query.filter_by(id=page_form_id).first()

        errors = []
        if not route:
            errors.append('Missing URL route')

        if errors:
            page = Pages(title, html, route)
            return render_template('/admin/editor.html', page=page)

        if page:
            page.title = title
            page.route = route
            page.html = html
            page.auth_required = auth_required

            if page_op == 'publish':
                page.draft = False

            db.session.commit()

            data = {
                'result': 'success',
                'operation': page_op,
                'page': {
                    'id': page.id,
                    'route': page.route,
                    'title': page.title
                }
            }

            db.session.close()
            cache.clear()
            return jsonify(data)

        if page_op == 'publish':
            page = Pages(title,
                         route,
                         html,
                         draft=False,
                         auth_required=auth_required)
        elif page_op == 'save':
            page = Pages(title, route, html, auth_required=auth_required)

        db.session.add(page)
        db.session.commit()

        data = {
            'result': 'success',
            'operation': page_op,
            'page': {
                'id': page.id,
                'route': page.route,
                'title': page.title
            }
        }

        db.session.close()
        cache.clear()

        return jsonify(data)

    pages = Pages.query.all()
    return render_template('admin/pages.html', pages=pages)
Exemple #12
0
def load(app):

    shell = Blueprint('shell', __name__, template_folder='shell-templates')
    app.register_blueprint(shell, url_prefix='/shell')
    page = Pages('shell', """ """)
    auth = Blueprint('auth', __name__)

    shellexists = Pages.query.filter_by(route='shell').first()
    if not shellexists:
        db.session.add(page)
        db.session.commit()

    @app.route('/shell', methods=['GET'])
    def shell_view():
        if not authed():
            return redirect(url_for('auth.login', next=request.path))

        return render_template('shell.html', root=request.script_root)

    @app.route('/register', methods=['POST', 'GET'])
    def register():
        if not can_register():
            return redirect(url_for('auth.login'))
        if request.method == 'POST':
            errors = []
            name = request.form['name']
            email = request.form['email']
            password = request.form['password']

            name_len = len(name) < 2
            names = Teams.query.add_columns('name',
                                            'id').filter_by(name=name).first()
            emails = Teams.query.add_columns(
                'email', 'id').filter_by(email=email).first()
            pass_short = len(password) == 0
            pass_long = len(password) > 32
            valid_email = re.match(
                r"(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)",
                request.form['email'])

            if not valid_email:
                errors.append("That email doesn't look right")
            if names:
                errors.append('That team name is already taken')
            if emails:
                errors.append('That email has already been used')
            if pass_short:
                errors.append('Pick a longer password')
            if pass_long:
                errors.append('Pick a shorter password')
            if name_len:
                errors.append('Pick a longer team name')

            if len(errors) > 0:
                return render_template('register.html',
                                       errors=errors,
                                       name=request.form['name'],
                                       email=request.form['email'],
                                       password=request.form['password'])
            else:
                with app.app_context():
                    team = Teams(name, email.lower(), password)
                    db.session.add(team)
                    db.session.commit()
                    db.session.flush()
                    shell = xmlrpclib.ServerProxy('http://*****:*****@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)",
                    email)

                password = request.form['password'].strip()
                pass_short = len(password) == 0
                pass_long = len(password) > 32


                if ('password' in request.form.keys() and not len(request.form['password']) == 0) and \
                    (not bcrypt_sha256.verify(request.form.get('confirm').strip(), user.password)):
                    errors.append(
                        "Your old password doesn't match what we have.")
                if not valid_email:
                    errors.append("That email doesn't look right")
                if not get_config('prevent_name_change'
                                  ) and names and name != session['username']:
                    errors.append('That team name is already taken')
                if emails and emails.id != session['id']:
                    errors.append('That email has already been used')
                if not get_config('prevent_name_change') and name_len:
                    errors.append('Pick a longer team name')
                if website.strip() and not validate_url(website):
                    errors.append("That doesn't look like a valid URL")
                if pass_short:
                    errors.append('Pick a longer password')
                if pass_long:
                    errors.append('Pick a shorter password')

                if len(errors) > 0:
                    return render_template('profile.html',
                                           name=name,
                                           email=email,
                                           website=website,
                                           affiliation=affiliation,
                                           country=country,
                                           errors=errors)
                else:
                    team = Teams.query.filter_by(id=session['id']).first()
                    if not get_config('prevent_name_change'):
                        team.name = name
                    if team.email != email.lower():
                        team.email = email.lower()
                        if get_config('verify_emails'):
                            team.verified = False
                    session['username'] = team.name

                    if 'password' in request.form.keys() and not len(
                            request.form['password']) == 0:
                        team.password = bcrypt_sha256.encrypt(
                            request.form.get('password'))
                        password = request.form['password'].strip()

                    team.website = website
                    team.affiliation = affiliation
                    team.country = country

                    name = team.name

                    if password:
                        shell = xmlrpclib.ServerProxy('http://localhost:8000',
                                                      allow_none=True)
                        shell.change_user(name, password)

                    db.session.commit()
                    db.session.close()
                    return redirect(url_for('views.profile'))
            else:
                user = Teams.query.filter_by(id=session['id']).first()
                name = user.name
                email = user.email
                website = user.website
                affiliation = user.affiliation
                country = user.country
                prevent_name_change = get_config('prevent_name_change')
                confirm_email = get_config(
                    'verify_emails') and not user.verified
                return render_template('profile.html',
                                       name=name,
                                       email=email,
                                       website=website,
                                       affiliation=affiliation,
                                       country=country,
                                       prevent_name_change=prevent_name_change,
                                       confirm_email=confirm_email)
        else:
            return redirect(url_for('auth.login'))

    app.view_functions['auth.reset_password'] = reset_password
    app.view_functions['auth.register'] = register
    app.view_functions['views.profile'] = profile
Exemple #13
0
def load_bp(admin_route, base_route, plugin_dir='.'):
    @writeups_bp.route(f"{base_route}/assets/<path:path>", methods=["GET"])
    def assets(path: str):
        return send_from_directory(f"{plugin_dir}/assets", path)

    @writeups_bp.route(admin_route, methods=["POST"])
    @admins_only
    def update_config():
        form = request.form.to_dict()
        del form['nonce']

        challenges = defaultdict(lambda: {})

        for k, v in form.items():
            match = re.match(r'(?P<id>\d+)-(?P<prop>[a-zA-Z0-9-_]+)', k)
            if match:
                challenges[int(match.group('id'))][match.group('prop')] = v
            else:
                print(f"Unrecognized form key {k}")

        for challenge_id, props in challenges.items():
            challenge = Challenges.query.get(challenge_id)
            if 'accepting_wu' in props:
                if not challenge.writeup_challenge:
                    challenge.writeup_challenge = WriteUpChallenges(
                        name=f"Write-Up for {challenge.name}",
                        description='',
                        category='Write-Ups')
                challenge.writeup_challenge.value = props.get('wu_value', 5)
                challenge.writeup_challenge.solve_req = 'vis_before_solve' not in props
                submit_str = f"\n\n[Submit a write-up]({url_for('writeups.edit_writeup', challenge_id=challenge.id)}) for this challenge (+{challenge.writeup_challenge.value} pts.) or [view others']({url_for('writeups.writeups', challenge=challenge.id)}) write-ups."
                submit_re = r'\[Submit a write-up]\(.+\) for this challenge \(\+\d+ pts\.\) or \[view others\']\(.+\) write-ups\.'
                if not re.search(submit_re, challenge.description):
                    challenge.description += submit_str
                else:
                    challenge.description = re.sub(submit_re, submit_str,
                                                   challenge.description)
            elif challenge.writeup_challenge:
                db.session.delete(challenge.writeup_challenge)

        db.session.commit()
        return get_config()

    @writeups_bp.route(admin_route, methods=["GET"])
    @admins_only
    def get_config():
        challenges = db.session.query(Challenges).filter(
            Challenges.type != 'writeup').all()
        submissions = (db.session.query(Submissions).join(
            WriteUpChallenges,
            Submissions.challenge_id == WriteUpChallenges.id)).all()

        rows = []
        for challenge in challenges:
            rows.append({
                'id':
                challenge.id,
                'name':
                challenge.name,
                'value':
                challenge.value,
                'accepting_wu':
                bool(challenge.writeup_challenge),
                'wu_value':
                challenge.writeup_challenge.value
                if challenge.writeup_challenge else 0,
                'solve_req':
                challenge.writeup_challenge.solve_req
                if challenge.writeup_challenge else True
            })

        return render_template("writeups_admin.html",
                               challenges=rows,
                               writeups=submissions)

    @writeups_bp.route(base_route, methods=["GET"])
    @during_ctf_time_only
    @authed_only
    def writeups():
        user = get_current_user()
        page = db.session.query(Pages).filter(
            Pages.route == base_route).one_or_none()

        if user.type == 'admin':
            visible_writeups = (db.session.query(Submissions).join(
                WriteUpChallenges,
                Submissions.challenge_id == WriteUpChallenges.id))
        else:
            solves_ids = [s.challenge_id
                          for s in user.team.solves] if user.team else []
            visible_writeups = (db.session.query(Submissions).join(
                WriteUpChallenges,
                Submissions.challenge_id == WriteUpChallenges.id).filter(
                    WriteUpChallenges.for_id.in_(solves_ids)
                    | ~WriteUpChallenges.solve_req
                    | (Submissions.user_id == user.id)))

        if 'challenge' in request.args:
            visible_writeups = visible_writeups.filter(
                WriteUpChallenges.for_id == request.args['challenge'])

        visible_writeups = visible_writeups.all()
        return render_template("writeups.html",
                               writeups=visible_writeups,
                               page_content=page.content if page else '')

    @writeups_bp.route(f"{base_route}/<int:writeup_id>", methods=["GET"])
    @during_ctf_time_only
    @authed_only
    def view_writeup(writeup_id: int):
        user = get_current_user()
        writeup = db.session.query(Submissions).get(writeup_id)
        error = {}
        content = ''
        editable = False

        if writeup.challenge.type != 'writeup':
            return redirect(url_for('writeups.writeups'))

        challenge = (db.session.query(Challenges).filter(
            Challenges.type != 'writeup').filter(
                Challenges.writeup_challenge ==
                writeup.challenge).one_or_none())

        if not challenge or not challenge.writeup_challenge:
            return redirect(url_for('writeups.writeups'))

        if (user.type == 'admin' or not challenge.writeup_challenge.solve_req
                or challenge.id in (s.challenge_id for s in user.team.solves)
                or writeup.user.id == user.id):
            content = cmarkgfm.github_flavored_markdown_to_html(
                writeup.provided, options=cmarkgfmOptions.CMARK_OPT_SAFE)
            if writeup.user.id == user.id or user.type == 'admin':
                editable = True
        else:
            error = {
                'heading':
                '403',
                'msg':
                'Sorry, you must solve this challenge before viewing write-ups for it'
            }
        return render_template("view_writeup.html",
                               challenge=challenge,
                               content=content,
                               error=error,
                               user=writeup.user,
                               editable=editable)

    @writeups_bp.route(f"{base_route}/<int:challenge_id>/edit",
                       methods=["GET", "POST"])
    @during_ctf_time_only
    @authed_only
    def edit_writeup(challenge_id: int):
        user = get_current_user()
        challenge = (db.session.query(Challenges).filter(
            Challenges.id == challenge_id).filter(
                Challenges.type != 'writeup').one_or_none())

        if not challenge or not challenge.writeup_challenge:
            return redirect(url_for('writeups.writeups'))

        solves = [s.challenge_id for s in user.team.solves
                  ] if user.team else [s.challenge_id for s in user.solves]

        if challenge.id not in solves:
            return render_template(
                "edit_writeup.html",
                challenge=challenge,
                error={
                    'heading':
                    '403',
                    'msg':
                    'Sorry, you must solve the challenge before submitting a write-up'
                })

        writeup = (db.session.query(Submissions).filter(
            Submissions.challenge_id == challenge.writeup_challenge.id).filter(
                Submissions.user_id == user.id).one_or_none())

        if not writeup:
            team_wu_solve = (db.session.query(Solves).filter(
                Solves.challenge_id == challenge.writeup_challenge.id).filter(
                    Solves.team_id == user.team.id).one_or_none())
            if team_wu_solve:
                writeup = Duplicate(
                    challenge=challenge.writeup_challenge,
                    user=user,
                    team=user.team,
                    ip=request.remote_addr,
                    provided='',
                )
            else:
                writeup = Solves(
                    challenge=challenge.writeup_challenge,
                    user=user,
                    team=user.team,
                    ip=request.remote_addr,
                    provided='',
                )
            db.session.add(writeup)
            db.session.flush()

        if request.method == 'POST':
            writeup.provided = request.form.to_dict().get('content', '')
            res = redirect(
                url_for('writeups.view_writeup', writeup_id=writeup.id))
            db.session.commit()
            return res
        elif request.method == 'GET':
            return render_template("edit_writeup.html",
                                   challenge=challenge,
                                   writeup=writeup)

    # Add the Write-Ups page to pages so it appears in the nav bar
    if not db.session.query(Pages).filter(
            Pages.route == base_route).one_or_none():
        with open(f"{plugin_dir}/assets/writeups_default.html", 'r') as fd:
            db.session.add(
                Pages(title='Write-Ups',
                      route=base_route,
                      content=fd.read(),
                      draft=False,
                      hidden=False,
                      auth_required=True))
            db.session.commit()

    return writeups_bp
Exemple #14
0
def load(app):
    #    register_plugin_assets_directory(app, base_path='/plugins/ctfd-shell-plugin/assets/')
    app.db.create_all()

    shellexists = Pages.query.filter_by(route='shell').first()
    if not shellexists:
        title = 'Shell'
        route = 'shell'
        html = """<style>
#shell-container {
  width: calc(100vw - 20px);
  padding: 0 0 0 0;
}

#shell-help {
  text-align: center;
  height:75px;
  margin: 0 0 0 0;
  border-radius: 5px;
}

#shell {
  height: calc(100vh - 200px);
  width: 100%;
}
</style>

<div id="shell-container" class="container shell-container">
  <div id="shell-help" class="alert alert-info alert-dismissable">
    <a href="#" class="close" data-dismiss="alert" aria-label="close">&times;</a>
    <p>Use the username and password you registered with to log in.</p>
    <p>You may also log in over ssh on port 2222</p>
  </div>
  <div class>
    <iframe id="shell" src="https://192.168.1.1/shell/" id="gadget0" name="gadget0" frameborder="1"></iframe>
  </div>
</div>
        """

        page = Pages(title, route, html, draft=False, auth_required=True)
        db.session.add(page)
        db.session.commit()

    connection = pika.BlockingConnection(
        pika.ConnectionParameters('localhost'))
    channel = connection.channel()
    channel.queue_declare(queue='shell_queue', durable=True)

    def new_register():
        logger = logging.getLogger('regs')
        if not utils.can_register():
            return redirect(url_for('auth.login'))
        if request.method == 'POST':
            errors = []
            name = request.form['name']
            email = request.form['email']
            password = request.form['password']

            name_len = len(name) == 0
            names = Teams.query.add_columns('name',
                                            'id').filter_by(name=name).first()
            emails = Teams.query.add_columns(
                'email', 'id').filter_by(email=email).first()
            pass_short = len(password) == 0
            pass_long = len(password) > 128
            valid_email = utils.check_email_format(request.form['email'])
            team_name_email_check = utils.check_email_format(name)

            if not valid_email:
                errors.append("Please enter a valid email address")
            if names:
                errors.append('That team name is already taken')
            if team_name_email_check is True:
                errors.append('Your team name cannot be an email address')
            if emails:
                errors.append('That email has already been used')
            if pass_short:
                errors.append('Pick a longer password')
            if pass_long:
                errors.append('Pick a shorter password')
            if name_len:
                errors.append('Pick a longer team name')

            if len(errors) > 0:
                return render_template('register.html',
                                       errors=errors,
                                       name=request.form['name'],
                                       email=request.form['email'],
                                       password=request.form['password'])
            else:
                with app.app_context():
                    team = Teams(name, email.lower(), password)
                    db.session.add(team)
                    db.session.commit()
                    db.session.flush()

                    message = json.dumps(["add", name, password])

                    channel.basic_publish(
                        exchange='',
                        routing_key='shell_queue',
                        body=message,
                        properties=pika.BasicProperties(
                            delivery_mode=2,  # make message persistent
                        ))

                    session['username'] = team.name
                    session['id'] = team.id
                    session['admin'] = team.admin
                    session['nonce'] = utils.sha512(os.urandom(10))

                    if utils.can_send_mail() and utils.get_config(
                            'verify_emails'
                    ):  # Confirming users is enabled and we can send email.
                        logger = logging.getLogger('regs')
                        logger.warn(
                            "[{date}] {ip} - {username} registered (UNCONFIRMED) with {email}"
                            .format(
                                date=time.strftime("%m/%d/%Y %X"),
                                ip=utils.get_ip(),
                                username=request.form['name'].encode('utf-8'),
                                email=request.form['email'].encode('utf-8')))
                        utils.verify_email(team.email)
                        db.session.close()
                        return redirect(url_for('auth.confirm_user'))
                    else:  # Don't care about confirming users
                        if utils.can_send_mail(
                        ):  # We want to notify the user that they have registered.
                            utils.sendmail(
                                request.form['email'],
                                "You've successfully registered for {}".format(
                                    utils.get_config('ctf_name')))

            logger.warn(
                "[{date}] {ip} - {username} registered with {email}".format(
                    date=time.strftime("%m/%d/%Y %X"),
                    ip=utils.get_ip(),
                    username=request.form['name'].encode('utf-8'),
                    email=request.form['email'].encode('utf-8')))
            db.session.close()
            return redirect(url_for('challenges.challenges_view'))
        else:
            return render_template('register.html')

    def new_profile(data=None):
        logger = logging.getLogger('logins')

        if data is not None:
            try:
                s = TimedSerializer(app.config['SECRET_KEY'])
                name = s.loads(utils.base64decode(data, urldecode=True),
                               max_age=1800)
            except BadTimeSignature:
                return render_template('reset_password.html',
                                       errors=['Your link has expired'])
            except (BadSignature, TypeError, base64.binascii.Error):
                return render_template('reset_password.html',
                                       errors=['Your reset token is invalid'])

            if request.method == "GET":
                return render_template('reset_password.html', mode='set')
            if request.method == "POST":
                team = Teams.query.filter_by(name=name).first_or_404()
                team.password = bcrypt_sha256.encrypt(
                    request.form['password'].strip())
                db.session.commit()
                logger.warn(
                    "[{date}] {ip} -  successful password reset for {username}"
                    .format(date=time.strftime("%m/%d/%Y %X"),
                            ip=utils.get_ip(),
                            username=team.name.encode('utf-8')))

                password = request.form['password'].strip()

                if password:
                    message = json.dumps(["change", name, password])

                    channel.basic_publish(
                        exchange='',
                        routing_key='shell_queue',
                        body=message,
                        properties=pika.BasicProperties(
                            delivery_mode=2,  # make message persistent
                        ))
                db.session.close()
                return redirect(url_for('auth.login'))

        if request.method == 'POST':
            email = request.form['email'].strip()
            team = Teams.query.filter_by(email=email).first()

            errors = []

            if utils.can_send_mail() is False:
                return render_template(
                    'reset_password.html',
                    errors=[
                        'Email could not be sent due to server misconfiguration'
                    ])

            if not team:
                return render_template(
                    'reset_password.html',
                    errors=[
                        'If that account exists you will receive an email, please check your inbox'
                    ])

            utils.forgot_password(email, team.name)

            return render_template(
                'reset_password.html',
                errors=[
                    'If that account exists you will receive an email, please check your inbox'
                ])
        return render_template('reset_password.html')

    def new_reset_pass():
        if utils.authed():
            if request.method == "POST":
                errors = []

                name = request.form.get('name').strip()
                email = request.form.get('email').strip()
                website = request.form.get('website').strip()
                affiliation = request.form.get('affiliation').strip()
                country = request.form.get('country').strip()

                user = Teams.query.filter_by(id=session['id']).first()

                if not utils.get_config('prevent_name_change'):
                    names = Teams.query.filter_by(name=name).first()
                    name_len = len(request.form['name']) == 0

                emails = Teams.query.filter_by(email=email).first()
                valid_email = utils.check_email_format(email)

                if utils.check_email_format(name) is True:
                    errors.append('Team name cannot be an email address')

                if ('password' in request.form.keys() and not len(request.form['password']) == 0) and \
                        (not bcrypt_sha256.verify(request.form.get('confirm').strip(), user.password)):
                    errors.append(
                        "Your old password doesn't match what we have.")
                if not valid_email:
                    errors.append("That email doesn't look right")
                if not utils.get_config(
                        'prevent_name_change'
                ) and names and name != session['username']:
                    errors.append('That team name is already taken')
                if emails and emails.id != session['id']:
                    errors.append('That email has already been used')
                if not utils.get_config('prevent_name_change') and name_len:
                    errors.append('Pick a longer team name')
                if website.strip() and not utils.validate_url(website):
                    errors.append("That doesn't look like a valid URL")

                if len(errors) > 0:
                    return render_template('profile.html',
                                           name=name,
                                           email=email,
                                           website=website,
                                           affiliation=affiliation,
                                           country=country,
                                           errors=errors)

                else:
                    team = Teams.query.filter_by(id=session['id']).first()
                    if team.name != name:
                        if not utils.get_config('prevent_name_change'):
                            team.name = name
                            session['username'] = team.name
                    if team.email != email.lower():
                        team.email = email.lower()
                        if utils.get_config('verify_emails'):
                            team.verified = False

                    if 'password' in request.form.keys() and not len(
                            request.form['password']) == 0:
                        team.password = bcrypt_sha256.encrypt(
                            request.form.get('password'))
                        message = json.dumps(["change", name, password])

                        channel.basic_publish(
                            exchange='',
                            routing_key='shell_queue',
                            body=message,
                            properties=pika.BasicProperties(
                                delivery_mode=2,  # make message persistent
                            ))

                    team.website = website
                    team.affiliation = affiliation
                    team.country = country
                    db.session.commit()
                    db.session.close()

                    return redirect(url_for('views.profile'))
            else:
                user = Teams.query.filter_by(id=session['id']).first()
                name = user.name
                email = user.email
                website = user.website
                affiliation = user.affiliation
                country = user.country
                prevent_name_change = utils.get_config('prevent_name_change')
                confirm_email = utils.get_config(
                    'verify_emails') and not user.verified
                return render_template('profile.html',
                                       name=name,
                                       email=email,
                                       website=website,
                                       affiliation=affiliation,
                                       country=country,
                                       prevent_name_change=prevent_name_change,
                                       confirm_email=confirm_email)
        else:
            return redirect(url_for('auth.login'))

    app.view_functions['auth.register'] = new_register
    app.view_functions['views.profile'] = new_profile
    app.view_functions['auth.reset_password'] = new_reset_pass
Exemple #15
0
def import_ctf(backup, segments=None, erase=False):
    side_db = dataset.connect(get_config('SQLALCHEMY_DATABASE_URI'))
    if segments is None:
        segments = ['challenges', 'teams', 'both', 'metadata']

    if not zipfile.is_zipfile(backup):
        raise TypeError

    backup = zipfile.ZipFile(backup)

    groups = {
        'challenges': [
            'challenges',
            'files',
            'tags',
            'keys',
            'hints',
        ],
        'teams': [
            'teams',
            'tracking',
            'awards',
        ],
        'both': [
            'solves',
            'wrong_keys',
            'unlocks',
        ],
        'metadata': [
            'alembic_version',
            'config',
            'pages',
            'containers',
        ]
    }

    ## Need special handling of metadata
    if 'metadata' in segments:
        meta = groups['metadata']
        segments.remove('metadata')
        meta.remove('alembic_version')

        for item in meta:
            table = side_db[item]
            path = "db/{}.json".format(item)
            data = backup.open(path).read()

            ## Some JSON files will be empty
            if data:
                if item == 'config':
                    saved = json.loads(data)
                    for entry in saved['results']:
                        key = entry['key']
                        value = entry['value']
                        set_config(key, value)

                elif item == 'pages':
                    saved = json.loads(data)
                    for entry in saved['results']:
                        route = entry['route']
                        html = entry['html']
                        page = Pages.query.filter_by(route=route).first()
                        if page:
                            page.html = html
                        else:
                            page = Pages(route, html)
                            db.session.add(page)
                        db.session.commit()

                elif item == 'containers':
                    saved = json.loads(data)
                    for entry in saved['results']:
                        name = entry['name']
                        buildfile = entry['buildfile']
                        container = Containers.query.filter_by(
                            name=name).first()
                        if container:
                            container.buildfile = buildfile
                        else:
                            container = Containers(name, buildfile)
                            db.session.add(container)
                        db.session.commit()

    for segment in segments:
        group = groups[segment]
        for item in group:
            table = side_db[item]
            path = "db/{}.json".format(item)
            data = backup.open(path).read()
            if data:
                saved = json.loads(data)
                for entry in saved['results']:
                    entry_id = entry.pop('id', None)
                    table.insert(entry)
            else:
                continue
Exemple #16
0
def setup():
    # with app.app_context():
        # admin = Teams.query.filter_by(admin=True).first()

    if not is_setup():
        if not session.get('nonce'):
            session['nonce'] = sha512(os.urandom(10))
        if request.method == 'POST':
            ctf_name = request.form['ctf_name']
            ctf_name = set_config('ctf_name', ctf_name)

            ## CSS
            css = set_config('start', '')

            ## Admin user
            name = request.form['name']
            email = request.form['email']
            password = request.form['password']
            admin = Teams(name, email, password)
            admin.admin = True
            admin.banned = True

            ## Index page
            page = Pages('index', """<div class="container main-container">
    <img class="logo" src="{0}/static/original/img/logo.png" />
    <h3 class="text-center">
        Welcome to a cool CTF competition organized by <a href="https://www.facebook.com/CLB/Tinhoc.TLU">TLIT Club</a> and info at <a href="http://thanglongit.me/d/87">thanglongit.me</a>
    </h3>

    <h4 class="text-center">
        <a href="{0}/login">Click here</a> to login and  play  now!
    </h4>
</div>""".format(request.script_root))

            #max attempts per challenge
            max_tries = set_config("max_tries",0)

            ## Start time
            start = set_config('start', None)
            end = set_config('end', None)

            ## Challenges cannot be viewed by unregistered users
            view_challenges_unregistered = set_config('view_challenges_unregistered', None)

            ## Allow/Disallow registration
            prevent_registration = set_config('prevent_registration', None)

            ## Verify emails
            verify_emails = set_config('verify_emails', None)

            mail_server = set_config('mail_server', None)
            mail_port = set_config('mail_port', None)
            mail_tls = set_config('mail_tls', None)
            mail_ssl = set_config('mail_ssl', None)
            mail_username = set_config('mail_username', None)
            mail_password = set_config('mail_password', None)

            setup = set_config('setup', True)

            db.session.add(page)
            db.session.add(admin)
            db.session.commit()
            db.session.close()
            app.setup = False
            return redirect(url_for('views.static_html'))
        return render_template('setup.html', nonce=session.get('nonce'))
    return redirect(url_for('views.static_html'))