Wargame/Web
[Dreamhack.io] baby-sqlite
youung
2022. 11. 23. 20:32
728x90
반응형
페이지에 접속하면 위와 같이 뜬다.
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
반응형