Fixing DOM XSS issues, upload issues, and usability issues

selenium-screenshot-testing
CodeKevin 2015-03-16 16:03:58 -04:00
parent 95e015abe6
commit ac83c8a576
9 changed files with 53 additions and 24 deletions

1
.gitignore vendored
View File

@ -56,3 +56,4 @@ target/
*.db
*.log
.idea/
static/uploads

View File

@ -268,10 +268,14 @@ def init_admin(app):
md5hash = hashlib.md5(os.urandom(64)).hexdigest()
# BUG NEEDS TO GO TO S3
if not os.path.exists(os.path.join(app.config['UPLOAD_FOLDER'], md5hash)):
os.makedirs(os.path.join(app.config['UPLOAD_FOLDER'], md5hash))
base = os.path.dirname(os.path.dirname(__file__))
## mod_wsgi does some sad things with cwd so the upload directory needs to be shifted a bit
if not os.path.exists(os.path.join(base, app.config['UPLOAD_FOLDER'], md5hash)):
os.makedirs(os.path.join(base, app.config['UPLOAD_FOLDER'], md5hash))
f.save(os.path.join(app.config['UPLOAD_FOLDER'], md5hash, filename))
f.save(os.path.join(base, app.config['UPLOAD_FOLDER'], md5hash, filename))
## This needs to be relative to CTFd so doesn't nee base.
db_f = Files(chalid, os.path.join(app.config['UPLOAD_FOLDER'], md5hash, filename))
db.session.add(db_f)

View File

@ -60,11 +60,15 @@ Did you initiate a password reset?
return redirect('/login')
if request.method == 'POST':
errors = []
name_len = len(request.form['name']) == 0
names = Teams.query.add_columns('name', 'id').filter_by(name=request.form['name']).first()
emails = Teams.query.add_columns('email', 'id').filter_by(email=request.form['email']).first()
pass_short = len(request.form['password']) == 0
pass_long = len(request.form['password']) > 128
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 = re.match("[^@]+@[^@]+\.[^@]+", request.form['email'])
if not valid_email:
@ -84,7 +88,7 @@ Did you initiate a password reset?
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(request.form['name'], request.form['email'], request.form['password'])
team = Teams(name, email, password)
db.session.add(team)
db.session.commit()
if mailserver():
@ -102,8 +106,9 @@ Did you initiate a password reset?
def login():
if request.method == 'POST':
errors = []
name = request.form['name']
# team = Teams.query.filter_by(name=request.form['name'], password=sha512(request.form['password'])).first()
team = Teams.query.filter_by(name=request.form['name']).first()
team = Teams.query.filter_by(name=name).first()
if team and bcrypt_sha256.verify(request.form['password'], team.password):
try:
session.regenerate() # NO SESSION FIXATION FOR YOU

View File

@ -5,6 +5,7 @@ SQLALCHEMY_DATABASE_URI = 'sqlite:///ctfd.db'
SESSION_TYPE = "filesystem"
SESSION_FILE_DIR = "/tmp/flask_session"
SESSION_COOKIE_HTTPONLY = True
PERMANENT_SESSION_LIFETIME = 604800 # 7 days in seconds
HOST = ".ctfd.io"
UPLOAD_FOLDER = os.path.normpath('static/uploads')

View File

@ -75,8 +75,8 @@ def admins_only(f):
def ctftime():
""" Checks whether it's CTF time or not. """
start = Config.query.filter_by(key="start").first().value
end = Config.query.filter_by(key="end").first().value
start = get_config("start")
end = get_config("end")
if start:
start = int(start)
@ -84,7 +84,7 @@ def ctftime():
end = int(end)
if start and end:
if start < time.time() and time.time() < end:
if start < time.time() < end:
# Within the two time bounds
return True

View File

@ -135,13 +135,16 @@ def init_views(app):
affiliation = request.form.get('affiliation')
country = request.form.get('country')
user = Teams.query.filter_by(id=session['id']).first()
names = Teams.query.filter_by(name=name).first()
emails = Teams.query.filter_by(email=email).first()
valid_email = re.match("[^@]+@[^@]+\.[^@]+", email)
name_len = len(request.form['name']) == 0
if not bcrypt_sha256.verify(request.form.get('confirm').strip(), names.password):
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")
@ -151,7 +154,7 @@ def init_views(app):
errors.append('That email has already been used')
if name_len:
errors.append('Pick a longer team name')
if not validate_url(website):
if website.strip() and not validate_url(website):
errors.append("That doesn't look like a valid URL")
if len(errors) > 0:
@ -160,6 +163,8 @@ def init_views(app):
team = Teams.query.filter_by(id=session['id']).first()
team.name = name
team.email = email
session['username'] = name
if 'password' in request.form.keys() and not len(request.form['password']) == 0:
team.password = bcrypt_sha256.encrypt(request.form.get('password'))
team.website = website

View File

@ -9,6 +9,10 @@ String.prototype.format = String.prototype.f = function() {
return s;
};
function htmlentities(string) {
return $('<div/>').text(string).html();
}
var challenges;
function loadchal(id) {
@ -149,7 +153,7 @@ function getsolves(id){
var id = teams[i].id;
var name = teams[i].name;
var date = moment(teams[i].date).local().format('LLL');
box.append('<tr><td><a href="/team/{0}">{1}</td><td>{2}</td></tr>'.format(id, name, date));
box.append('<tr><td><a href="/team/{0}">{1}</td><td>{2}</td></tr>'.format(id, htmlentities(name), date));
};
});
}

View File

@ -9,12 +9,16 @@ String.prototype.format = String.prototype.f = function() {
return s;
};
function htmlentities(string) {
return $('<div/>').text(string).html();
}
function updatescores () {
$.get('/scores', function( data ) {
teams = $.parseJSON(JSON.stringify(data));
$('#scoreboard > tbody').empty()
for (var i = 0; i < teams['teams'].length; i++) {
row = "<tr><td>{0}</td><td><a href='/team/{1}'>{2}</a></td><td>{3}</td></tr>".format(i+1, teams['teams'][i].id, teams['teams'][i].name, teams['teams'][i].score)
row = "<tr><td>{0}</td><td><a href='/team/{1}'>{2}</a></td><td>{3}</td></tr>".format(i+1, teams['teams'][i].id, htmlentities(teams['teams'][i].name), teams['teams'][i].score)
$('#scoreboard > tbody').append(row)
};
});

View File

@ -120,7 +120,6 @@
{% block scripts %}
<script>
function load_update_modal(id, name, email, website, affiliation, country){
var modal_form = $('#user form');
@ -144,11 +143,17 @@ $('#update-user').click(function(e){
for (var i = 0; i < data['data'].length; i++) {
if (data['data'][i] == 'success'){
var row = $('tr[name='+id+']')
row.find('.team-name').text( $.grep(user_data, function(e){ return e.name == 'name'; })[0]['value'] )
row.find('.team-email').text( $.grep(user_data, function(e){ return e.name == 'email'; })[0]['value'] )
row.find('.team-website').attr('href', $.grep(user_data, function(e){ return e.name == 'website'; })[0]['value'] )
row.find('.team-affiliation').text( $.grep(user_data, function(e){ return e.name == 'affiliation'; })[0]['value'] )
row.find('.team-country').text( $.grep(user_data, function(e){ return e.name == 'country'; })[0]['value'] )
console.log($.grep(user_data, function(e){ return e.name == 'name'; })[0]['value'])
console.log(row.find('.team-name > a'))
row.find('.team-name > a').text( $.grep(user_data, function(e){ return e.name == 'name'; })[0]['value'] );
row.find('.team-email').text( $.grep(user_data, function(e){ return e.name == 'email'; })[0]['value'] );
row.find('.team-website > a').empty()
var website = $.grep(user_data, function(e){ return e.name == 'website'; })[0]['value']
row.find('.team-website').append($('<a>').attr('href', website).text(website));
row.find('.team-affiliation').text( $.grep(user_data, function(e){ return e.name == 'affiliation'; })[0]['value'] );
row.find('.team-country').text( $.grep(user_data, function(e){ return e.name == 'country'; })[0]['value'] );
$('#user').foundation('reveal', 'close');
}
else{