mirror of https://github.com/JohnHammond/CTFd.git
Fixing DOM XSS issues, upload issues, and usability issues
parent
95e015abe6
commit
ac83c8a576
|
@ -56,3 +56,4 @@ target/
|
|||
*.db
|
||||
*.log
|
||||
.idea/
|
||||
static/uploads
|
|
@ -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)
|
||||
|
||||
|
|
19
CTFd/auth.py
19
CTFd/auth.py
|
@ -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
|
||||
|
|
|
@ -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')
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
};
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
});
|
||||
|
|
|
@ -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{
|
||||
|
|
Loading…
Reference in New Issue