Added a login template and put together a base for the server code.

master
John Hammond 2016-08-17 10:58:30 -04:00
parent 1acd05d3b3
commit 10ae797fa5
9 changed files with 723 additions and 1 deletions

View File

@ -16,6 +16,10 @@ File & Directory Information
This directory holds some code from a recent CTF platform I tried to build on my own. I am using elements from it, so I just snagged to code to be able to cherry-pick off of it and change what I need to get this project rolling. __Do not consider it a part of this project; it is _not_. It is just included as a convenience for me while the BearShop project is still be developed.__
* [`static/`](static/)
This folder is required by [Flask] and it is where all "static" files live, like things for [CSS] or images or fonts or [HTML] templates.
* [`schema.sql`](schema.sql)
This is the [SQL] schema file that is used to create the database for the webpage. It should create and define tables for things like users, the products on sale, and anything else that may be deemed necessary.
@ -25,10 +29,15 @@ File & Directory Information
This is the [`bash`][bash] script that I planned on using to initially create the server. It sets up the database, creates private keys to be used, and modifies a "base" rendition of the server [Python] script to add all of the configuration variables that can be set _in the_ [`setup.sh`](setup.sh) script.
* [`server_base.py`](server_base.py)
This is actual source code of the web application. __! Remember, it is _not_ what you will actually run to deploy the server; the [`setup.sh`](setup.sh) script will take it and configure it, to create a new, functional `server.py` which is what you will run when you deploy.__
[Python]: https://www.python.org/
[Flask]: http://flask.pocoo.org/
[SQL]: https://en.wikipedia.org/wiki/SQL
[bash]: https://en.wikipedia.org/wiki/Bash_(Unix_shell)
[bash]: https://en.wikipedia.org/wiki/Bash_(Unix_shell)
[CSS]: https://www.w3.org/Style/CSS/Overview.en.html
[HTML]: https://en.wikipedia.org/wiki/HTML

287
ctf_skeleton/server_base.py Normal file
View File

@ -0,0 +1,287 @@
#!/usr/bin/env python
from flask import Flask
from flask import render_template, request, session, g, url_for, flash, get_flashed_messages, redirect
import sqlite3
import json
import sys, os
from colorama import *
import sys
from threading import Thread
from time import sleep
from uuid import uuid4
from passlib.hash import sha256_crypt
from contextlib import closing
debug = True
init( autoreset = True )
if (debug):
def success( string ):
print Fore.GREEN + Style.BRIGHT + "[+] " + string
def error( string ):
sys.stderr.write( Fore.RED + Style.BRIGHT + "[-] " + string + "\n" )
def warning( string ):
print Fore.YELLOW + "[!] " + string
else:
def success( string ): pass
def error( string ): pass
def warning( string ): pass
# ===========================================================================
DATABASE = '$DATABASE'
CERTIFICATE = '$CERTIFICATE_FILE'
PRIVATE_KEY = '$PRIVATEKEY_FILE'
SECRET_KEY = 'this_key_needs_to_be_used_for_session_variables'
if DATABASE == '$DATABASE':
error("This server has not yet been configured with a database file!")
exit(-1)
if CERTIFICATE == '$CERTIFICATE_FILE':
error("This server has not yet been configured with a certificate!")
exit(-1)
if PRIVATE_KEY == '$PRIVATEKEY_FILE':
error("This server has not yet been configured with a private key!")
exit(-1)
app = Flask( __name__ )
app.config.from_object(__name__)
def init_db():
with closing(connect_db()) as db:
with app.open_resource('schema.sql', mode='r') as f:
db.cursor().executescript(f.read())
db.commit()
def connect_db():
return sqlite3.connect( app.config['DATABASE'] )
@app.before_request
def before_request():
g.db = connect_db()
@app.teardown_request
def teardown_request(exception):
db = getattr(g, 'db', None)
if db is not None:
db.close()
# --------------------------------------------------------------------
@app.route("/")
def index():
if not ( session['logged_in'] ):
return redirect('login')
@app.route("/login", methods=["GET", "POST"])
def login():
error = ""
if request.method == "POST":
cur = g.db.execute('select username, password from users')
# username, password_hash
users = dict(( row[0], row[1] ) for row in cur.fetchall())
if not request.form['username'] in users.iterkeys():
error = 'This username is not in the database!'
else:
if not ( sha256_crypt.verify( request.form['password'], users[request.form['username']] ) ):
error = "Incorrect password!"
else:
session_login( request.form['username'] )
return redirect( "about" )
return render_template( 'login.html' )
# @app.route("/register", methods=["GET", "POST"])
# def register():
# cur = g.db.execute('select username from users')
# usernames = [row[0] for row in cur.fetchall() ]
# error = ""
# if request.method == "POST":
# if unicode(request.form['username']) in usernames:
# error = 'This username is already in use!'
# elif (request.form['password'] == ""):
# error = "You must supply a password!"
# elif request.form['password'] != request.form['confirm']:
# error = 'Your passwords do not match!'
# else:
# # I use this for command-line submission...
# identifier = str(uuid4())
# cur = g.db.execute('insert into users (username, password, solved_challenges, score, last_submission, uuid) values ( ?, ?, ?, ?, ?, ? )', [
# request.form['username'],
# sha256_crypt.encrypt( request.form['password']),
# "", # No challenges completed
# 0, # no score.
# 0, # no last submission time,
# identifier # and a completely unique idenitifier
# ] )
# g.db.commit()
# flash("Hello " + request.form['username'] + ", you have successfully registered!")
# session_login( request.form['username'] )
# return redirect( "challenges" )
# return render( 'register.html', error = error )
# @app.route("/scoreboard")
# def scoreboard():
# cur = g.db.execute('select username, score from users order by score desc, last_submission asc')
# response = cur.fetchall()
# users = [ { "username": row[0], "score": row[1] } for row in response]
# return render("scoreboard.html", users = users )
# @app.route("/logout")
# def logout():
# session_logout()
# return redirect("about")
# @app.route("/")
# @app.route("/about")
# def about(): return render("about.html", app_about=configuration['app_about'])
# @app.route("/challenges")
# def challenges_page():
# if not ( session['logged_in'] ):
# return render("login.html", error = "You must log in to be able to see the challenges!")
# try:
# cur = g.db.execute('select uuid from users where username =?',
# [ session['username'],] )
# uuid = cur.fetchone()[0]
# except Exception as e:
# print error(e.message)
# uuid = ''
# return render("challenges.html", challenges = configuration['services'], url=request.url_root, session_value = uuid )
# @app.route("/check_answer", methods=["GET", "POST"])
# def check_answer():
# global correct_answers
# if request.method == "POST":
# if request.form['answer'] in session['solved_challenges']:
# return json.dumps({'correct': -1});
# if ( request.form['answer'] in correct_answers.keys() ):
# flag = request.form['answer']
# new_score = int(session['score']) + correct_answers[flag]
# cur = g.db.execute("update users set score = (?), last_submission = (SELECT strftime('%s')) where username = (?)", [
# new_score,
# session['username']
# ] );
# session['solved_challenges'].append( request.form['answer'] )
# session['score'] = new_score
# g.db.commit();
# return json.dumps({'correct': 1, 'new_score': new_score});
# else:
# return json.dumps({'correct': 0});
# @app.route("/submit", methods=[ "POST" ])
# def submit():
# global correct_answers
# if request.method == "POST":
# if ( request.form['flag'] in correct_answers.keys() ):
# flag = request.form['flag']
# cur = g.db.execute('select score, solved_challenges from users where uuid = (?)',
# [ request.form['uuid'], ])
# current_score, solved_challenges = cur.fetchone()
# solved_challenges = solved_challenges.split()
# if ( flag in solved_challenges ):
# return 'You already submitted this flag!\n'
# print solved_challenges
# new_score = current_score + correct_answers[flag]
# solved_challenges.append( flag + " " )
# cur = g.db.execute("update users set score = (?), last_submission = (SELECT strftime('%s')), solved_challenges = (?) where uuid = (?)", [
# new_score,
# ' '.join(solved_challenges),
# request.form['uuid']
# ] );
# # session['solved_challenges'].append( request.form['flag'] )
# session['score'] = new_score
# g.db.commit();
# # return json.dumps({'correct': 1, 'new_score': new_score});
# return 'Correct!\n';
# else:
# # return json.dumps({'correct': 0});
# return 'Incorrect!\n';
def session_login( username ):
flash("You were successfully logged in!")
# cur = g.db.execute('select solved_challenges, score from users where username = (?)',
# [username])
# solved_challenges, score = cur.fetchone()
session['logged_in'] = True
# session['username'] = username
# session['score'] = score
# session['solved_challenges'] = []
def session_logout():
flash("You have been successfully logged out.")
session['logged_in'] = False
# session.pop('username')
# session.pop('score')
if ( __name__ == "__main__" ):
context = (CERTIFICATE, PRIVATE_KEY)
app.run( host="0.0.0.0", debug=False, ssl_context=context, port = 444 )

287
server_base.py Normal file
View File

@ -0,0 +1,287 @@
#!/usr/bin/env python
from flask import Flask
from flask import render_template, request, session, g, url_for, flash, get_flashed_messages, redirect
import sqlite3
import json
import sys, os
from colorama import *
import sys
from threading import Thread
from time import sleep
from uuid import uuid4
from passlib.hash import sha256_crypt
from contextlib import closing
debug = True
init( autoreset = True )
if (debug):
def success( string ):
print Fore.GREEN + Style.BRIGHT + "[+] " + string
def error( string ):
sys.stderr.write( Fore.RED + Style.BRIGHT + "[-] " + string + "\n" )
def warning( string ):
print Fore.YELLOW + "[!] " + string
else:
def success( string ): pass
def error( string ): pass
def warning( string ): pass
# ===========================================================================
DATABASE = '$DATABASE'
CERTIFICATE = '$CERTIFICATE_FILE'
PRIVATE_KEY = '$PRIVATEKEY_FILE'
SECRET_KEY = 'this_key_needs_to_be_used_for_session_variables'
if DATABASE == '$DATABASE':
error("This server has not yet been configured with a database file!")
exit(-1)
if CERTIFICATE == '$CERTIFICATE_FILE':
error("This server has not yet been configured with a certificate!")
exit(-1)
if PRIVATE_KEY == '$PRIVATEKEY_FILE':
error("This server has not yet been configured with a private key!")
exit(-1)
app = Flask( __name__ )
app.config.from_object(__name__)
def init_db():
with closing(connect_db()) as db:
with app.open_resource('schema.sql', mode='r') as f:
db.cursor().executescript(f.read())
db.commit()
def connect_db():
return sqlite3.connect( app.config['DATABASE'] )
@app.before_request
def before_request():
g.db = connect_db()
@app.teardown_request
def teardown_request(exception):
db = getattr(g, 'db', None)
if db is not None:
db.close()
# --------------------------------------------------------------------
@app.route("/")
def index():
if not ( session['logged_in'] ):
return redirect('login')
@app.route("/login", methods=["GET", "POST"])
def login():
error = ""
if request.method == "POST":
cur = g.db.execute('select username, password from users')
# username, password_hash
users = dict(( row[0], row[1] ) for row in cur.fetchall())
if not request.form['username'] in users.iterkeys():
error = 'This username is not in the database!'
else:
if not ( sha256_crypt.verify( request.form['password'], users[request.form['username']] ) ):
error = "Incorrect password!"
else:
session_login( request.form['username'] )
return redirect( "about" )
return render_template( 'login.html' )
# @app.route("/register", methods=["GET", "POST"])
# def register():
# cur = g.db.execute('select username from users')
# usernames = [row[0] for row in cur.fetchall() ]
# error = ""
# if request.method == "POST":
# if unicode(request.form['username']) in usernames:
# error = 'This username is already in use!'
# elif (request.form['password'] == ""):
# error = "You must supply a password!"
# elif request.form['password'] != request.form['confirm']:
# error = 'Your passwords do not match!'
# else:
# # I use this for command-line submission...
# identifier = str(uuid4())
# cur = g.db.execute('insert into users (username, password, solved_challenges, score, last_submission, uuid) values ( ?, ?, ?, ?, ?, ? )', [
# request.form['username'],
# sha256_crypt.encrypt( request.form['password']),
# "", # No challenges completed
# 0, # no score.
# 0, # no last submission time,
# identifier # and a completely unique idenitifier
# ] )
# g.db.commit()
# flash("Hello " + request.form['username'] + ", you have successfully registered!")
# session_login( request.form['username'] )
# return redirect( "challenges" )
# return render( 'register.html', error = error )
# @app.route("/scoreboard")
# def scoreboard():
# cur = g.db.execute('select username, score from users order by score desc, last_submission asc')
# response = cur.fetchall()
# users = [ { "username": row[0], "score": row[1] } for row in response]
# return render("scoreboard.html", users = users )
# @app.route("/logout")
# def logout():
# session_logout()
# return redirect("about")
# @app.route("/")
# @app.route("/about")
# def about(): return render("about.html", app_about=configuration['app_about'])
# @app.route("/challenges")
# def challenges_page():
# if not ( session['logged_in'] ):
# return render("login.html", error = "You must log in to be able to see the challenges!")
# try:
# cur = g.db.execute('select uuid from users where username =?',
# [ session['username'],] )
# uuid = cur.fetchone()[0]
# except Exception as e:
# print error(e.message)
# uuid = ''
# return render("challenges.html", challenges = configuration['services'], url=request.url_root, session_value = uuid )
# @app.route("/check_answer", methods=["GET", "POST"])
# def check_answer():
# global correct_answers
# if request.method == "POST":
# if request.form['answer'] in session['solved_challenges']:
# return json.dumps({'correct': -1});
# if ( request.form['answer'] in correct_answers.keys() ):
# flag = request.form['answer']
# new_score = int(session['score']) + correct_answers[flag]
# cur = g.db.execute("update users set score = (?), last_submission = (SELECT strftime('%s')) where username = (?)", [
# new_score,
# session['username']
# ] );
# session['solved_challenges'].append( request.form['answer'] )
# session['score'] = new_score
# g.db.commit();
# return json.dumps({'correct': 1, 'new_score': new_score});
# else:
# return json.dumps({'correct': 0});
# @app.route("/submit", methods=[ "POST" ])
# def submit():
# global correct_answers
# if request.method == "POST":
# if ( request.form['flag'] in correct_answers.keys() ):
# flag = request.form['flag']
# cur = g.db.execute('select score, solved_challenges from users where uuid = (?)',
# [ request.form['uuid'], ])
# current_score, solved_challenges = cur.fetchone()
# solved_challenges = solved_challenges.split()
# if ( flag in solved_challenges ):
# return 'You already submitted this flag!\n'
# print solved_challenges
# new_score = current_score + correct_answers[flag]
# solved_challenges.append( flag + " " )
# cur = g.db.execute("update users set score = (?), last_submission = (SELECT strftime('%s')), solved_challenges = (?) where uuid = (?)", [
# new_score,
# ' '.join(solved_challenges),
# request.form['uuid']
# ] );
# # session['solved_challenges'].append( request.form['flag'] )
# session['score'] = new_score
# g.db.commit();
# # return json.dumps({'correct': 1, 'new_score': new_score});
# return 'Correct!\n';
# else:
# # return json.dumps({'correct': 0});
# return 'Incorrect!\n';
def session_login( username ):
flash("You were successfully logged in!")
# cur = g.db.execute('select solved_challenges, score from users where username = (?)',
# [username])
# solved_challenges, score = cur.fetchone()
session['logged_in'] = True
# session['username'] = username
# session['score'] = score
# session['solved_challenges'] = []
def session_logout():
flash("You have been successfully logged out.")
session['logged_in'] = False
# session.pop('username')
# session.pop('score')
if ( __name__ == "__main__" ):
context = (CERTIFICATE, PRIVATE_KEY)
app.run( host="0.0.0.0", debug=False, ssl_context=context, port = 444 )

0
setup.sh Normal file → Executable file
View File

109
static/css/master.css Normal file
View File

@ -0,0 +1,109 @@
html{
height: 100%;
width: 100%;
}
@font-face {
font-family: 'Share Tech';
src: url('../fonts/Share Tech.ttf');
}
body{
font-family: 'Share Tech';
margin: 0px 0px;
padding: 0px 0px;
background-color: gray;
/* Permalink - use to edit and share this gradient: http://colorzilla.com/gradient-editor/#0043af+0,0056ce+46,ffb76b+52,ffa73d+57,ff7c00+88,ff7f04+100 */
background: #0043af; /* Old browsers */
background: -moz-linear-gradient(top, #0043af 0%, #0056ce 46%, #ffb76b 52%, #ffa73d 57%, #ff7c00 88%, #ff7f04 100%); /* FF3.6-15 */
background: -webkit-linear-gradient(top, #0043af 0%,#0056ce 46%,#ffb76b 52%,#ffa73d 57%,#ff7c00 88%,#ff7f04 100%); /* Chrome10-25,Safari5.1-6 */
background: linear-gradient(to bottom, #0043af 0%,#0056ce 46%,#ffb76b 52%,#ffa73d 57%,#ff7c00 88%,#ff7f04 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#0043af', endColorstr='#ff7f04',GradientType=0 ); /* IE6-9 */
}
#login_box_background{
max-width: 600px;
max-height: 400px;
padding: 2%;
position: absolute;
top:0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
background-color: white;
opacity: .1;
}
#login_box{
/*font-family: 'Share Tech';*/
/*background-color: white;*/
color: white;
font-size: larger;
/*margin-top: 30%;*/
border-top: 1px solid black;
border-bottom: 1px solid black;
max-width: 600px;
max-height: 400px;
padding: 2%;
position: absolute;
top:0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
/*width: 100%;*/
/*padding: 10%;*/
}
input{
display: block;
margin:auto;
width: 90%;
height: 40px;
font-size: x-large;
padding: 5px;
}
h1{
border-bottom: 1px solid white;
}
#login{
text-transform: uppercase;
text-align: center;
width: 95%;
height: 60px;
background-color: red;
border: none;
display: block;
font-family: 'Share Tech';
font-size: xx-large;
color: white;
/*vertical-align: middle;*/
margin: 10px;
}
#register{
text-transform: uppercase;
text-align: center;
width: 95%;
line-height: 60px;
background-color: blue;
display: block;
font-size: xx-large;
margin: 10px;
/*font-weight: bold;*/
/*vertical-align: middle;*/
}

BIN
static/fonts/Share Tech.ttf Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

30
static/login.html Normal file
View File

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title> Login -- USCGA BearShop</title>
<link rel="stylesheet" type="text/css" href="css/master.css">
</head>
<body>
<div id="login_box_background"></div>
<div id="login_box">
<h1>Welcome the USCGA BearShop!</h1>
<p>
Please login below with your EDU e-mail and your BearShop password.
</p>
<form>
<input type="text" name="email">
<input type="password" name="password">
<input type="submit" value="LOGIN" id="login">
</form>
<span id="register"> REGISTER </span>
</div>
</body>
</html>