문제 설명


웹 사이트 들어가 보니,

이렇게 기본적인 형태를 갖추고 있다. 

Home, About, Contact 셋 다 눌러 봐도 이 화면이다. 

 

로그인을 눌러 보면 username이나 pw 입력하라는 건 안 나오고,

userlevel을 입력하라고 한다...

 

문제에선 챗지피티 이용하라고는 했는데 아무런 지식 없이는 어떤 형식으로 질문을 해야 할지 모르겠어서,

일단 소스코드를 먼저 열어 봤다.

#!/usr/bin/python3
from flask import Flask, request, render_template, g
import sqlite3
import os
import binascii

app = Flask(__name__)
app.secret_key = os.urandom(32)

try:
    FLAG = open('./flag.txt', 'r').read()
except:
    FLAG = '[**FLAG**]'

DATABASE = "database.db"
if os.path.exists(DATABASE) == False:
    db = sqlite3.connect(DATABASE)
    db.execute('create table users(userid char(100), userpassword char(100), userlevel integer);')
    db.execute(f'insert into users(userid, userpassword, userlevel) values ("guest", "guest", 0), ("admin", "{binascii.hexlify(os.urandom(16)).decode("utf8")}", 0);')
    db.commit()
    db.close()

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

def query_db(query, one=True):
    cur = get_db().execute(query)
    rv = cur.fetchall()
    cur.close()
    return (rv[0] if rv else None) if one else rv

@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:
        userlevel = request.form.get('userlevel')
        res = query_db(f"select * from users where userlevel='{userlevel}'")
        if res:
            userid = res[0]
            userlevel = res[2]
            print(userid, userlevel)
            if userid == 'admin' and userlevel == 0:
                return f'hello {userid} flag is {FLAG}'
            return f'<script>alert("hello {userid}");history.go(-1);</script>'
        return '<script>alert("wrong");history.go(-1);</script>'

app.run(host='0.0.0.0', port=8000)

대략 훑어 보니,

    db.execute(f'insert into users(userid, userpassword, userlevel) values ("guest", "guest", 0), ("admin", "{binascii.hexlify(os.urandom(16)).decode("utf8")}", 0);')

이런 부분을 대충 짐작해 보자면

userid=guest, userpassword=guest, userlevel=0 인 계정 하나,

userin=admin, userpassword={binascii.hexlify(os.urandom(16)).decode("utf8")}, userlevel=0인 계정 하나

이렇게 두 개의 계정이 있는 듯하다.

아마 플래그를 얻기 위해서 key가 되는 건 admin이겠지

 

어쨌든 위 내용을 바탕으로 login 창에서 userlevel 0 입력해 봤더니,

게스트 계정으로만 로그인이 된다. 

 

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'GET':
        return render_template('login.html')
    else:
        userlevel = request.form.get('userlevel')
        res = query_db(f"select * from users where userlevel='{userlevel}'")
        if res:
            userid = res[0]
            userlevel = res[2]
            print(userid, userlevel)
            if userid == 'admin' and userlevel == 0:
                return f'hello {userid} flag is {FLAG}'
            return f'<script>alert("hello {userid}");history.go(-1);</script>'
        return '<script>alert("wrong");history.go(-1);</script>'

app.run(host='0.0.0.0', port=8000)

여기서 보면 users 테이블에서 userlevel과 일치하는 행의 모든 컬럼을 반환한다고 한다.

그리고 userid가 admin 문자열과 일치할 경우 flag 값을 출력한다.

 

and 연산자를 사용해 userid 컬럼 값이 admin인 쿼리를 입력하면 문제가 해결된다고 한다. 

플래그 얻기 성공!

+ Recent posts