PK" flask/app.py# Copyright 2023 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import gevent.monkey gevent.monkey.patch_all() from flask import Flask from flask_sqlalchemy import SQLAlchemy from flask_login import LoginManager import requests import os db = SQLAlchemy() PHP_HOST = 'under-construction-php' TOKEN = os.environ.get('MIGRATOR_TOKEN','missing_token') MYSQL_USER = os.environ.get('MYSQL_USER') MYSQL_PASSWORD = os.environ.get('MYSQL_PASSWORD') MYSQL_DATABASE = os.environ.get('MYSQL_DATABASE') DB_HOST = os.environ.get('DB_HOST') def create_app(): app = Flask(__name__) app.config['SECRET_KEY'] = os.environ['FLASK_SECRET_KEY'] app.config['SQLALCHEMY_DATABASE_URI'] = f'mysql+pymysql://{MYSQL_USER}:{MYSQL_PASSWORD}@{DB_HOST}/{MYSQL_DATABASE}' db.init_app(app) import models import authorized_routes import unauthorized_routes with app.app_context(): db.create_all() login_manager = LoginManager() login_manager.login_view = 'authorized_routes.login' login_manager.init_app(app) @login_manager.user_loader def load_user(user_id): return models.User.query.get(int(user_id)) app.register_blueprint(authorized_routes.authorized) app.register_blueprint(unauthorized_routes.unauthorized) @app.cli.command("reset_db") def reset_db(): with app.app_context(): models.User.query.delete() db.session.commit() requests.post(f"http://{PHP_HOST}:1337/account_cleanup.php", headers={"token": TOKEN}) return app PK> flask/authorized_routes.py# Copyright 2023 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os import logging from flask_login import login_user, login_required, logout_user from flask import Blueprint, render_template, redirect, url_for, request, flash from werkzeug.security import generate_password_hash, check_password_hash import models import requests from app import db, PHP_HOST, TOKEN authorized = Blueprint('authorized', __name__) @authorized.route('/login') def login(): return render_template('login.html') @authorized.route('/login', methods=['POST']) def login_post(): username = request.form.get('username') password = request.form.get('password') remember = True if request.form.get('remember') else False user = models.User.query.filter_by(username=username).first() if not user or not check_password_hash(user.password, password): flash('Please check your login details and try again.') return redirect(url_for('authorized.login')) login_user(user, remember=remember) return redirect(url_for('unauthorized.profile')) @authorized.route('/signup') def signup(): return render_template('signup.html', tiers=models.Tier) @authorized.route('/signup', methods=['POST']) def signup_post(): raw_request = request.get_data() username = request.form.get('username') password = request.form.get('password') tier = models.Tier(request.form.get('tier')) if(tier == models.Tier.GOLD): flash('GOLD tier only allowed for the CEO') return redirect(url_for('authorized.signup')) if(len(username) > 15 or len(username) < 4): flash('Username length must be between 4 and 15') return redirect(url_for('authorized.signup')) user = models.User.query.filter_by(username=username).first() if user: flash('Username address already exists') return redirect(url_for('authorized.signup')) new_user = models.User(username=username, password=generate_password_hash(password, method='sha256'), tier=tier.name) db.session.add(new_user) db.session.commit() requests.post(f"http://{PHP_HOST}:1337/account_migrator.php", headers={"token": TOKEN, "content-type": request.headers.get("content-type")}, data=raw_request) return redirect(url_for('authorized.login')) @authorized.route('/logout') @login_required def logout(): logout_user() return redirect(url_for('unauthorized.index')) PK6<flask/models.py# Copyright 2023 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from flask_login import UserMixin from app import db import enum from sqlalchemy import Enum class Tier(enum.Enum): BLUE = 'blue' RED = 'red' GREEN = 'green' GOLD = 'gold' class User(UserMixin, db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(15), unique=True) password = db.Column(db.String(100)) tier = db.Column(Enum(Tier)) PK󀧸flask/requirements.txtclick==8.1.3 Flask==2.2.3 Flask-Login==0.6.2 Flask-SQLAlchemy==3.0.3 greenlet==2.0.2 itsdangerous==2.1.2 Jinja2==3.1.2 MarkupSafe==2.1.2 SQLAlchemy==2.0.10 typing_extensions==4.5.0 Werkzeug==2.2.3 requests==2.29.0 gunicorn==20.1.0 pymysql==1.0.3 gevent==22.10.2 cryptography==41.0.1 PKxUEflask/unauthorized_routes.py# Copyright 2023 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from flask import Blueprint, render_template from flask_login import login_required, current_user from app import db unauthorized = Blueprint('unauthorized', __name__) @unauthorized.route('/') def index(): return render_template('index.html') @unauthorized.route('/profile') @login_required def profile(): return render_template('profile.html', username=current_user.username, tier=current_user.tier) PKɍVII%flask/__pycache__/app.cpython-310.pyco _od@s>ddlmZddlmZddlmZddlZeZddZdS))Flask) SQLAlchemy) LoginManagerNcstt}tjd|jd<d|jd<t|ddlddl}ddl }| t Wdn1s5wYt }d|_ |||jfdd}||j||j |S) NFLASK_SECRET_KEY SECRET_KEYzsqlite:////tmp/db/db.sqliteSQLALCHEMY_DATABASE_URIrz auth.logincsjjt|S)N)Userquerygetint)user_idmodels[/usr/local/google/home/epuig/ctf/2023-challenges/web-password-verify/challenge/flask/app.py load_userszcreate_app..load_user)r__name__osenvironconfigdbinit_apprauthmain app_context create_allr login_view user_loaderregister_blueprint)apprr login_managerrrr r create_apps$       r!) flaskrflask_sqlalchemyr flask_loginrrrr!rrrrs   PK˦&flask/__pycache__/main.cpython-310.pyco _odd@sbddlmZmZddlmZmZddlmZedeZ e dddZ e ded d Z d S) ) Blueprintrender_template)login_required current_user)dbmain/cCstdS)Nz index.html)rr r \/usr/local/google/home/epuig/ctf/2023-challenges/web-password-verify/challenge/flask/main.pyindexsr z/profilecCstdtjdS)Nz profile.html)username)rrr r r r r profile sr N) flaskrr flask_loginrrappr__name__rrouter r r r r r s   PKSv  flask/templates/index.html {% extends "wrapper.html" %} {% block content %}

Welcome, our app is currently under construction

Please feel free to login or create an account.

{% endblock %} PK6flask/templates/login.html {% extends "wrapper.html" %} {% block content %}

Login

{% with messages = get_flashed_messages() %} {% if messages %}
{{ messages[0] }}
{% endif %} {% endwith %}
{% endblock %} PKƁ>dflask/templates/profile.html {% extends "wrapper.html" %} {% block content %}

Hello, {{ username }}!

Your tier is {{tier.name}}.

{% endblock %} PKtW>flask/templates/signup.html {% extends "wrapper.html" %} {% block content %}

Sign Up

{% with messages = get_flashed_messages() %} {% if messages %}
{{ messages[0] }}. Go to login page.
{% endif %} {% endwith %}
{% endblock %} PK͹  flask/templates/wrapper.html Under Construction

{% block content %} {% endblock %}

PKڄphp/account_cleanup.phpexec("TRUNCATE TABLE Users;"); echo "Table truncated"; } catch (PDOException $e) { throw new PDOException( message: $e->getMessage(), code: (int) $e->getCode() ); } } ?> PKt`AAphp/account_migrator.phpexec("CREATE TABLE IF NOT EXISTS Users (username varchar(15) NOT NULL, password_hash varchar(60) NOT NULL, tier varchar(10) NOT NULL, PRIMARY KEY (username));"); $stmt = $pdo->prepare("INSERT INTO Users Values(?,?,?);"); $stmt->execute([$username, $hash, $tier]); echo "User inserted"; } catch (PDOException $e) { throw new PDOException( message: $e->getMessage(), code: (int) $e->getCode() ); } } ?> PK?SC php/index.php PHP login

PHP login

{$response}

"; } ?> prepare("SELECT password_hash, tier FROM Users WHERE username = ?"); $stmt->execute([$username]); if ($row = $stmt->fetch()) { if (password_verify($password, $row['password_hash'])) { return $row['tier']; } var_dump($row); } return NULL; } catch (PDOException $e) { throw new PDOException( message: $e->getMessage(), code: (int) $e->getCode() ); } } ?>PK php/style.css/* Copyright 2023 Google LLC Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ Body { background-color: gray; } .container { padding: 18px; background-color: darkgray; border: 2px solid black; margin-bottom: 24px; } input, button { font-size: large; width: 100%; margin: 12px 0px; margin-bottom: 24px; padding: 16px; display: inline-block; border: 2px solid black; box-sizing: border-box; } label { font-size: x-large; } button { font-size: larger; cursor: pointer; margin: 0px; } button:hover { opacity: 75%; } p { font-size: x-large; text-align: center; } h1 { text-align: center; }PK" flask/app.pyPK> *flask/authorized_routes.pyPK6<flask/models.pyPK󀧸flask/requirements.txtPKxUE3flask/unauthorized_routes.pyPKɍVII%Iflask/__pycache__/app.cpython-310.pycPK˦&!flask/__pycache__/main.cpython-310.pycPKSv  $flask/templates/index.htmlPK6(flask/templates/login.htmlPKƁ>d/flask/templates/profile.htmlPKtW>2flask/templates/signup.htmlPK͹  9flask/templates/wrapper.htmlPKڄKEphp/account_cleanup.phpPKt`AAKphp/account_migrator.phpPK?SC {Sphp/index.phpPK 8_php/style.cssPKbc