No FA¶
Files Provided¶
app.py:
from flask import Flask, render_template, request, flash, redirect, url_for, session, send_file
from dotenv import load_dotenv
import db
import os
import hashlib
import random
import time
load_dotenv()
app = Flask(__name__)
app.secret_key = os.getenv('SECRET_KEY')
@app.before_request
def initialize():
app.before_request_funcs[None].remove(initialize)
db.init_db()
@app.route("/")
def home():
if 'username' not in session or session['logged'] == 'false':
flash('Please login to access this page', 'red')
return redirect(url_for('login'))
flag = "No flag for you!!"
if session.get('username') == 'admin':
flag = os.getenv('FLAG')
return render_template("index.html", flag=flag)
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
user = db.get_user_by_username(username)
if user and hashlib.sha256(password.encode()).hexdigest() == user['password']:
if user['two_fa']:
# Generate OTP
otp = str(random.randint(1000, 9999))
session['otp_secret'] = otp
session['otp_timestamp'] = time.time()
session['username'] = username
session['logged'] = 'false'
# send OTP to mail ---
return redirect(url_for('two_fa'))
else:
session['username'] = username
session['logged'] = 'true'
flash('Login successful!', 'green')
return redirect(url_for('home'))
else:
flash('Invalid username or password', 'red')
return render_template('login.html')
@app.route('/two_fa', methods=['GET', 'POST'])
def two_fa():
if request.method == 'POST':
otp = request.form['otp']
stored_otp = session['otp_secret']
timestamp = session.get('otp_timestamp')
if stored_otp and otp == stored_otp and (time.time() - timestamp) < 120:
session['logged'] = 'true'
flash('Login successful!', 'green')
return redirect(url_for('home'))
else:
flash('Invalid OTP or OTP expired', 'red')
return render_template('2fa.html')
else:
return render_template('2fa.html')
@app.route('/logout')
def logout():
flash('You have been logged out.', 'green')
session.pop('username', None)
session['logged'] = 'false'
return redirect(url_for('login'))
users.db:
.
.
adminiamadmin@nfs.comc20fa16907343eef642d10f0bdb81bf629e6aaf6c906f26eabda079ca9e5ab67
.
.
Approach¶
Authentication:
if user and hashlib.sha256(password.encode()).hexdigest() == user['password']:
if user['two_fa']:
# Generate OTP
otp = str(random.randint(1000, 9999))
session['otp_secret'] = otp
session['otp_timestamp'] = time.time()
session['username'] = username
session['logged'] = 'false'
# send OTP to mail ---
return redirect(url_for('two_fa'))
There's no salt used in hashing, trying with JohnTheRipper and rockyou.txt:
./run/john --format=raw-sha256 --wordlist=./run/rockyou.txt ./hash.txt
Using default input encoding: UTF-8
Loaded 1 password hash (Raw-SHA256 [SHA256 256/256 AVX2 8x])
Warning: poor OpenMP scalability for this hash type, consider --fork=12
Will run 12 OpenMP threads
Note: Passwords longer than 18 [worst case UTF-8] to 55 [ASCII] rejected
Press 'q' or Ctrl-C to abort, 'h' for help, almost any other key for status
apple@123 (?)
1g 0:00:00:00 DONE (2026-03-15 22:33) 4.545g/s 9830Kp/s 9830Kc/s 9830KC/s bragaparasempre..Angelg7
Use the "--show --format=Raw-SHA256" options to display all of the cracked passwords reliably
Session completed.
Trying the password "apple@123" works!
OTP is stored in the session cookie, which can be decoded here
Flag got!