https://dreamhack.io/wargame/challenges/47/
#!/usr/bin/python3
from flask import Flask, request, render_template, make_response, redirect, url_for, session, g
import sqlite3
import hashlib
import os
import time, random
app = Flask(__name__)
app.secret_key = os.urandom(32)
DATABASE = "database.db"
userLevel = {
0 : 'guest',
1 : 'admin'
}
MAXRESETCOUNT = 5
try:
FLAG = open('./flag.txt', 'r').read()
except:
FLAG = '[**FLAG**]'
def makeBackupcode():
return random.randrange(100)
def get_db():
db = getattr(g, '_database', None)
if db is None:
db = g._database = sqlite3.connect(DATABASE)
db.row_factory = sqlite3.Row
return db
@app.teardown_appcontext
def close_connection(exception):
db = getattr(g, '_database', None)
if db is not None:
db.close()
@app.route('/')
def index():
return render_template('index.html')
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'GET':
return render_template('login.html')
else:
userid = request.form.get("userid")
password = request.form.get("password")
conn = get_db()
# mysql connection ์ฐ๊ฒฐ.
cur = conn.cursor()
# connection ์ผ๋ก ๋ถํฐ Dictionary cursor ์์ฑ.
user = cur.execute( 'SELECT * FROM user WHERE id = ? and pw = ?', ( userid, hashlib.sha256( password.encode() ).hexdigest() ) ).fetchone()
# excute : sql๋ฌธ ์คํ.(์ธ์๋ userid / password(sha256์ผ๋ก ์ํธํ๋.))
if user:
session['idx'] = user['idx']
session['userid'] = user['id']
session['name'] = user['name']
session['level'] = userLevel[ user['level'] ]
return redirect(url_for('index'))
return "<script>alert('Wrong id/pw');history.back(-1);</script>";
@app.route('/logout')
def logout():
session.clear()
return redirect(url_for('index'))
@app.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'GET':
return render_template('register.html')
else:
userid = request.form.get("userid")
password = request.form.get("password")
name = request.form.get("name")
conn = get_db()
cur = conn.cursor()
user = cur.execute('SELECT * FROM user WHERE id = ?', (userid,)).fetchone()
if user:
return "<script>alert('Already Exists userid.');history.back(-1);</script>";
backupCode = makeBackupcode()
sql = "INSERT INTO user(id, pw, name, level, backupCode) VALUES (?, ?, ?, ?, ?)"
cur.execute(sql, (userid, hashlib.sha256(password.encode()).hexdigest(), name, 0, backupCode))
conn.commit()
return render_template("index.html", msg=f"<b>Register Success.</b><br/>Your BackupCode : {backupCode}")
ใ
@app.route('/forgot_password', methods=['GET', 'POST'])
def forgot_password():
if request.method == 'GET':
return render_template('forgot.html')
else:
userid = request.form.get("userid")
newpassword = request.form.get("newpassword")
backupCode = request.form.get("backupCode", type=int)
conn = get_db()
cur = conn.cursor()
user = cur.execute('SELECT * FROM user WHERE id = ?', (userid,) ).fetchone()
if user:
# security for brute force Attack.
time.sleep(1)
if user['resetCount'] == MAXRESETCOUNT:
return "<script>alert('reset Count Exceed.');history.back(-1);</script>"
if user['backupCode'] == backupCode:
newbackupCode = makeBackupcode()
updateSQL = "UPDATE user set pw = ?, backupCode = ?, resetCount = 0 where idx = ?"
cur.execute(updateSQL, (hashlib.sha256(newpassword.encode()).hexdigest(), newbackupCode, str(user['idx'])))
msg = f"<b>Password Change Success.</b><br/>New BackupCode : {newbackupCode}"
else:
updateSQL = "UPDATE user set resetCount = resetCount+1 where idx = ?"
cur.execute(updateSQL, (str(user['idx'])))
msg = f"Wrong BackupCode !<br/><b>Left Count : </b> {(MAXRESETCOUNT-1)-user['resetCount']}"
conn.commit()
return render_template("index.html", msg=msg)
return "<script>alert('User Not Found.');history.back(-1);</script>";
@app.route('/user/<int:useridx>')
def users(useridx):
conn = get_db()
cur = conn.cursor()
user = cur.execute('SELECT * FROM user WHERE idx = ?;', [str(useridx)]).fetchone()
if user:
return render_template('user.html', user=user)
return "<script>alert('User Not Found.');history.back(-1);</script>";
@app.route('/admin')
def admin():
if session and (session['level'] == userLevel[1]):
# session๋ณ์์ ๊ฐ์ด ์กด์ฌ and (session['level'] == userLevel[1]) ์ธ ๊ฒฝ์ฐ์ FLAG ๋ฐํ.
return FLAG
return "Only Admin !"
app.run(host='0.0.0.0', port=8000)
- /login
- GET method ์ด๋ฉด
- ๋ค์ login.html ๋ก ๋ฆฌ๋ค์ด๋ ํ .
- POST method ์ด๋ฉด
- ๋ณ์ userid , password ์ ๊ฐ๊ฐ ์ฌ์ฉ์์ ์ ๋ ฅ์ ์ ์ฅ.
- SQL ๋ฌธ 'SELECT * FROM user WHERE id = ? and pw = ?'์ ์ธ์ ? ์ ๊ฐ๊ฐ userid ์ password์ ์ํธํ ๊ฐ์ ๋ฃ์ด์ ์คํํ์ฌ ์ถ๋ ฅ๊ฐ์ ๋ณ์ user ์ ์ ์ฅ.
- user ๊ฐ์ด ์กด์ฌํ๋ค๋ฉด
- session['idx'] = user['idx']
- session['userid'] = user['id']
- session['name'] = user['name']
- session['level'] = userLevel[ user['level'] ]
- ๊ทธ ํ index url๋ก ๋ฆฌ๋ค์ด๋ ํ .
- user ๊ฐ์ด ์กด์ฌํ์ง ์๋ค๋ฉด
- "Wrong id/pw"๋ผ๋ ๋ง๊ณผ ํจ๊ป ๊ฒฝ๊ณ ์ฐฝ์ ์ถ๋ ฅํ๊ณ ์ด์ ํ์ด์ง๋ก ๋ฆฌ๋ค์ด๋ ํ .
- GET method ์ด๋ฉด
- /logout
- session์ ๋น์ฐ๊ณ index url ๋ก ๋ฆฌ๋ค์ด๋ ํ .
- /register
- GET method ์ด๋ฉด
- ๋ค์ redirect
- POST method ์ด๋ฉด
- ๋ณ์ userid, password, name ์ ๊ฐ๊ฐ ์ฌ์ฉ์์ ์ ๋ ฅ๊ฐ๋ค์ ์ ์ฅ.
- user ๋ณ์์ SQL๋ฌธ "SELCET * FROM user WHERE id = ?"์ ์ธ์๊ฐ ? ์ userid ๋ณ์์ ๊ฐ์ ๋ฃ์ด์ ์คํํ ๊ฐ์ ์ ์ฅ.
- user ๋ณ์์ ๊ฐ์ด ์๋ค๋ฉด (์ค๋ณต๋ userid ์ธ ๊ฒฝ์ฐ)
- "Already exists userid."๋ผ๋ ๋ฉ์์ง์ ํจ๊ป ๊ฒฝ๊ณ ์ฐฝ์ ์ถ๋ ฅํ๊ณ ์ด์ ํ์ด์ง๋ก ๋ฆฌ๋ค์ด๋ ํ ์ํด.
- user ๋ณ์์ ๊ฐ์ด ์๋ค๋ฉด (์ค๋ณต๋ userid ๊ฐ ์๋ ๊ฒฝ์ฐ)
- backupCode ์ makebackupCode() ํจ์๋ฅผ ํตํด ์๋ก์ด ๋๋ค ๋ฐฑ์ ์ฝ๋๋ฅผ ์ ์ฅ.
- sql ์ด๋ผ๋ ๋ณ์์ "INSERT INTO user(id, pw, name, level, backupCode) Values( ?, ?, ?, ?, ?)" ๋ผ๋ ๋ฌธ์์ด ์ ์ฅ.
- sql ๋ณ์์ ๋ด๊ธด SQL๋ฌธ์ ์คํํ๋๋ฐ, ๊ฐ ์ธ์ ? ์ ์ฐจ๋ก๋๋ก [userid , ์ํธํํ password , name, 0 , backupCode] ๊ฐ๋ค์ ๋ฃ์ด์ ์คํ.
- "Register Success . Your backupCode : {backupCode}"๋ผ๋ ๋ฌธ์์ด๊ณผ ํจ๊ป ๊ฒฝ๊ณ ์ฐฝ์ ์ถ๋ ฅํ๊ณ backupCode๋ ๊ฐ์ด ์ถ๋ ฅ.
- GET method ์ด๋ฉด
- /forgot_password
- method ๊ฐ get ์ด๋ฉด
- ๋ค์ redirect
- method ๊ฐ post์ด๋ฉด
- ์ฌ์ฉ์์ ์ ๋ ฅ๊ฐ 3๊ฐ(userid , newpassword , backupCode)๋ฅผ ๋ฐ์.
- db์ user ํ
์ด๋ธ์ id ์์ฑ ์ค ์
๋ ฅ๊ฐ userid์ ๊ฐ๊ณผ ๊ฐ์ ๊ฒ์ด ์กด์ฌํ๋ฉด
- time.sleep(1)
- user['resetCount'] == MAXRESETCOUNT ๊ฐ True ์ด๋ฉด
- reset Count Exceed ๋ผ๋ ๋ง์ด ๋ด๊ธด ๊ฒฝ๊ณ ์ฐฝ์ ๋์ฐ๊ณ ์ด์ ํ์ด์ง๋ก ๋ฆฌ๋ค์ด๋ ํ .
- user['backupCode'] == backupCode ๊ฐ True ์ด๋ฉด
- newbackupCode ์ makeBackupcode() ํจ์๋ฅผ ํตํด ์๋ก์ด ๋๋ค๋ฌธ์๋ค์ ์ ์ฅ.
- updateSQL ์ด๋ผ๋ ๋ณ์์ "UPDATE user set pw = ?, backupCode = ?, resetCount = 0 where idx = ? " ์ด๋ผ๋ ๋ฌธ์์ด ์ ์ฅ.
- updateSQL์ ๋ด๊ธด ๋ฌธ์์ด์ ์คํํ๋๋ฐ, ์ฒซ๋ฒ์งธ ? ์๋ ์ฌ์ฉ์๊ฐ ์ ๋ ฅํ newpassword ๋ฅผ ๋ฃ์ด์ ์คํํ๊ณ ,
- ๋๋ฒ์งธ ? ์๋ newbackupCode์ ๋ด๊ธด ๋ฌธ์๋ฅผ ๋ฃ์ด์ ์คํํ๊ณ ,
- ์ธ๋ฒ์งธ ? ์๋ str(user['idx'])๋ฅผ ๋ฃ์ด์ ์คํํ๋ค.
- msg ๋ผ๋ ๋ณ์์ "Password change success , New backupCode : {newbackupCode}"๋ฅผ ์ ์ฅ.
- user['backupCode'] == backupCode ๊ฐ False ์ด๋ฉด
- updateSQL ์ด๋ผ๋ ๋ณ์์ "Update user set resetCount = resetCount + 1 where idx = ? " ์ ์ฅ.
- updateSQL ๋ณ์์ ๋ด๊ธด ๋ฌธ์์ด์ ์คํํ๋๋ฐ, ์ฒซ๋ฒ์งธ ์ธ์ ? ์ str(usr['idx']) ๋ฅผ ๋ฃ์ด์ ์คํ.
- msg ๋ผ๋ ๋ณ์์ " Wrong backupCode ! Left Count : {MAXRESETCOUNT - 1 } - user['resetcount'] " ์ ์ฅ.
- msg ๋ณ์์ ๋ด๊ธด ์ฝ๋๋ฅผ ์ถ๋ ฅ.
- db์ user ํ
์ด๋ธ์ id ์์ฑ ์ค ์
๋ ฅ๊ฐ userid์ ๊ฐ๊ณผ ๊ฐ์ ๊ฒ์ด ์กด์ฌํ์ง ์์ผ๋ฉด
- "User Not Found ๋ผ๋ ๋ง๊ณผ ํจ๊ป ๊ฒฝ๊ณ ์ฐฝ์ ๋์ฐ๊ณ ์ด์ ํ์ด์ง๋ก ์ด๋์ํด."
- method ๊ฐ get ์ด๋ฉด
- /user/<int:useridx>
- ์ฌ์ฉ์๊ฐ ์
๋ ฅํ useridx์ ๋ํด db์ user ํ
์ด๋ธ์ idx ์์ฑ์ ํด๋น ์
๋ ฅ๊ฐ์ด ์กด์ฌํ๋ฉด
- ํด๋น user์ ๋ํ user.html์ ๋ฆฌํด
- ์
๋ ฅ์ ํด๋นํ๋ user๊ฐ ์กด์ฌํ์ง ์์ผ๋ฉด
- "User not found"๋ผ๋ ๋ง์ด ๋ด๊ธด ๊ฒฝ๊ณ ์ฐฝ์ ๋์.
- ์ฌ์ฉ์๊ฐ ์
๋ ฅํ useridx์ ๋ํด db์ user ํ
์ด๋ธ์ idx ์์ฑ์ ํด๋น ์
๋ ฅ๊ฐ์ด ์กด์ฌํ๋ฉด
- /admin
- session and (session['level'] == userLevel[1]): ์ธ ์กฐ๊ฑด์ด ์ฐธ์ธ ๊ฒฝ์ฐ(userLevel[1]์ admin ์ด๋ค.)
- FLAG๋ฆฌํด.
- session and (session['level'] == userLevel[1]): ์ธ ์กฐ๊ฑด์ด ๊ฑฐ์ง์ธ ๊ฒฝ์ฐ
- " Only admin! " ์ถ๋ ฅ.
- session and (session['level'] == userLevel[1]): ์ธ ์กฐ๊ฑด์ด ์ฐธ์ธ ๊ฒฝ์ฐ(userLevel[1]์ admin ์ด๋ค.)
์ด ๋ฌธ์ ์ ํน์ง์ ์๊ธฐํด๋ณด์๋ฉด,
- /admin ํ์ด์ง์ ์ ๊ทผํ๋ ค๋ฉด level = userLevel[1] ์ด์ด์ผ ํ๋ค.
- userLevel ์ 1 ๊ณผ 0 ์ด ์๋ ๊ฒ์ผ๋ก ๋ณด์ด๋๋ฐ, 1 ์ admin ์ด๊ณ 0 ์ ์ผ๋ฐ์ฌ์ฉ์๋ก ๋ณด์ธ๋ค.
์๋๋ฉด ๋ด๊ฐ /register ์ ํตํด ๊ณ์ ์ ์์ฑํ๊ณ ๋ก๊ทธ์ธ ํ๋ฉด, userLevel ์ด 0 ์ด๊ธฐ ๋๋ฌธ์ด๋ค.
- /user/์ซ์ ๋ฅผ get ๋ฉ์๋๋ก ๋ณด๋ด๋ฉด ํด๋น ์ซ์์ useridx ๋ฅผ ๊ฐ์ง user์ [UserID , UserName, UserLevel]์ ์ถ๋ ฅํด์ค๋ค.
์ด๋ฅผ ํตํด UserLevel์ด 0์ธ ๊ณ์ ๊ณผ 1์ธ ๊ณ์ ์ ์์๋ผ ์ ์๋ค.
- /forgot_password ํ์ด์ง์๋ [userid , newPassword , backupCode]๋ฅผ ์ ๋ ฅํ ์ ์๋๋ฐ,
์ด๋, Submit ๋ฒํผ์ ํตํด ๋ฆฌํ์คํธ๋ฅผ ๋ณด๋ด๊ณ 1์ด ๋์ time.sleep(1) ๊ตฌ๊ฐ ์ด ์กด์ฌํ๋ค.
- ์ฝ๋๋ฅผ ์ดํด๋ณด๋ฉด , backupCode๋ makebackupCode() ํจ์๋ฅผ ํตํด ์์ฑํ๋๋ฐ,
๋ฐ๋ผ์ ์ด์ ์ฐ๋ฆฌ๋ /user/{์ซ์}
ํ์ด์ง์์ UserLevel ์ด 1 ์ธ ๊ณ์ ์ ์ฐพ์๋ธ ํ,
/forgot_password ํ์ด์ง์์
userid , newPassword , backupCode ๋ฅผ ์ ๋ ฅํ ๋,
ํด๋น ๊ณ์ ์ backupCode๋ง ์์๋ด์
๋ด ๋ง์๋๋ก newPassword ๋ฅผ ์ค์ ํ์ฌ ๋น๋ฐ๋ฒํธ๋ฅผ ๋ฐ๊ฟ๋ฒ๋ฆฐ ๋ค์์,
์ด ๊ณ์ ์ผ๋ก /login ์์ ๋ก๊ทธ์ธํ์ฌ FLAG ๋ฅผ ์ป์ด๋ด๋ฉด ๋๋๋ฐ, !!
backupCode ๋ 1~100 ๊น์ง์ ์ซ์ ๋ผ์ ํ๋ฒ์ ์์๋ด๊ธฐ ์ฝ์ง์๋ค .
5๋ฒ์ /forgot_password ํ์ด์ง์ ๋ณด์์กฐ์น๊ฐ ์์๋ค๋ฉด
1๋ถํฐ 100๊น์ง ๋์ ํด๋ณด๋ฉด ๋๋๋ฐ
๊ทธ๋ ์ง ์๊ธฐ ๋๋ฌธ์ ๋ชจ๋ ์ง์ ๋์ ํด๋ณด๋ ๊ฒ์ ๋ถ๊ฐ๋ฅํ๋ค.
๋ฐ๋ก ์ฝ๋๋ฅผ ๋ง๋ค์ด์ ํด๊ฒฐํด์ผํ ๊ฒ ๊ฐ๋ค.
์ ๋ชจ๋ฅด๊ฒ ๋ค. ..
':: DreamHack ๐ฉ > wargame - web' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[ dreamhack ] - [ web | csrf-2 ] (0) | 2022.04.05 |
---|---|
[ dreamhack ] - [ web | csrf -1 ] (0) | 2022.03.29 |
[ dreamhack ] - [ web | image-storage ] (0) | 2022.03.17 |
[ dreamhack ] - [ web | proxy-1 ] (0) | 2022.03.17 |
[ dreamhack ] - [ web | command-injection-1 ] (0) | 2022.03.16 |
๋๊ธ