Wargame/Web

[Dreamhack.io] baby-sqlite

youung 2022. 11. 23. 20:32
728x90
반응형

문제 정보

 

 

 

 

접속 시 보이는 화면
/login 페이지

페이지에 접속하면 위와 같이 뜬다.

login을 해야하는 페이지이다.

 

 

 

 

#!/usr/bin/env python3
#app.py

from flask import Flask, request, render_template, make_response, redirect, url_for, session, g
import urllib
import os
import sqlite3

app = Flask(__name__)
app.secret_key = os.urandom(32)
from flask import _app_ctx_stack

DATABASE = 'users.db'

def get_db():
    top = _app_ctx_stack.top
    if not hasattr(top, 'sqlite_db'):
        top.sqlite_db = sqlite3.connect(DATABASE)
    return top.sqlite_db


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


@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')

    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!'


@app.teardown_appcontext
def close_connection(exception):
    top = _app_ctx_stack.top
    if hasattr(top, 'sqlite_db'):
        top.sqlite_db.close()


if __name__ == '__main__':
    os.system('rm -rf %s' % DATABASE)
    with app.app_context():
        conn = get_db()
        conn.execute('CREATE TABLE users (uid text, upw text, level integer);')
        conn.execute("INSERT INTO users VALUES ('dream','cometrue', 9);")
        conn.commit()

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

소스 코드를 확인하면,

uid가 admin이면 flag가 출력된다는 것을 알 수 있다.

 

그러나, sqli_filter로 필터링이 되고 있어서 우회해야 한다.

 

 

 

query = f"SELECT uid FROM users WHERE uid='{uid}' and upw='{upw}' and level={level};"

 

위 커리문을 확인해보면, uid와 pwd는 싱글쿼터(')를 사용하므로

싱글쿼터가 필터링이 걸려있어 우회를 할 수 없다.

 

하지만, level은 싱글쿼터로 둘러싸여 있지 않아 파라미터 값을 전달해 SQL Injection이 가능하다.

 

 

 

쿼리문을 보면, select 할 때 uid 컬럼만 가져오고 있어서 union으로 admin을 입력하면 된다.

sqlite에서는  '||'가 문자열을 더해주는 기능을 가지고 있다.

(sqlite의 특징)

 

'+'가 필터링 되고 있으므로 '+' 대신에 '||'를 사용하자.

 

 

 

uid=test&upw=test&level=1/**/union/**/values(char(97)||char(100)||char(109)||char(105)||char(110))

/**/는 공백 대신에 사용하고, char를 통해 admin을 입력해준다.

(필터링 우회)

 

 

 

 

프록시 걸고 위 구문을 넣어서 보내주면 FLAG가 출력된다.

 

 

 

FLAG

DH{sql-lite-cass-lite}

 

 

728x90
반응형