71 lines
1.9 KiB
Python
71 lines
1.9 KiB
Python
#!/usr/bin/env python3
|
|
# app.py - minimal vulnerable blog demonstrating stored XSS
|
|
|
|
from flask import (
|
|
Flask,
|
|
request,
|
|
redirect,
|
|
url_for,
|
|
render_template,
|
|
make_response,
|
|
jsonify,
|
|
abort
|
|
)
|
|
import json, os
|
|
|
|
app = Flask(__name__)
|
|
DATA_DIR = 'data'
|
|
COMMENTS_FILE = os.path.join(DATA_DIR, 'comments.json')
|
|
ADMIN_TOKEN_FILE = os.path.join(DATA_DIR, 'admin_token.txt')
|
|
FLAG_FILE = "flag.txt"
|
|
|
|
def read_comments():
|
|
with open(COMMENTS_FILE,'r') as f:
|
|
return json.load(f)
|
|
|
|
def write_comments(comments):
|
|
with open(COMMENTS_FILE,'w') as f:
|
|
json.dump(comments, f)
|
|
|
|
def read_file(path):
|
|
with open(path, 'r') as f:
|
|
return f.read().strip()
|
|
|
|
@app.route('/')
|
|
def index():
|
|
return render_template('index.html')
|
|
|
|
@app.route('/post/<int:post_id>')
|
|
def post_view(post_id):
|
|
comments = read_comments()
|
|
return render_template('post.html', post_id=post_id, comments=comments)
|
|
|
|
@app.route('/comment', methods=['POST'])
|
|
def comment_post():
|
|
name = request.form.get('name','Anonymous')
|
|
comment = request.form.get('comment','')
|
|
comments = read_comments()
|
|
next_id = max([c.get('id',0) for c in comments], default=0) + 1
|
|
comments.append({'name':name,'comment':comment,'id':next_id})
|
|
write_comments(comments)
|
|
return redirect(url_for('post_view', post_id=1))
|
|
|
|
@app.route('/api/comments')
|
|
def api_comments():
|
|
# returns raw comments as JSON for convenience (admin UI might use this)
|
|
return jsonify(read_comments())
|
|
|
|
@app.route('/admin_login')
|
|
def admin_login():
|
|
token = request.args.get('token', '')
|
|
real_token = read_file(ADMIN_TOKEN_FILE)
|
|
if token != real_token:
|
|
abort(404)
|
|
|
|
# Create response that sets a cookie named 'session' containing the flag
|
|
resp = make_response(redirect(url_for('post_view', post_id=1)))
|
|
flag = read_file(FLAG_FILE)
|
|
|
|
resp.set_cookie('session', flag, samesite='Lax')
|
|
return resp
|