# Анализирование Сначала мы просмотрим веб-сайт, на веб-сайте есть такая форма входа ![](https://hackmd.io/_uploads/SJStgmtoh.png) Здесь у наc есть код для веб-сайта. ```py! #!/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 try: FLAG = open('./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) ``` Чтение `app.py` раскрывает его механизм работы: - При первой настройке БД удаляется и создается заново. - `uid` админа не вставляется. - Вводимые пользователем uid, upw and level вводятся в нижнем регистре. - Если результатом запроса является админ, то вернуть флаг. # Эксплуатация Чтобы выполнить SQL-инъекцию, нам нужно преодолеть несколько препятствий: - Столбец uid из таблицы пользователей не содержит значение admin. - Пользовательские входные данные uid и upw нельзя эксплуатировать SQL-инъекций, поскольку вход фильтруется. - Вот у нас есть черный список, вводимые пользователем данные не могут содержать никаких пробелов, выключая пробелы, табуляции и новые строки, слов "admin" "select" ... - UNION [ALL] SELECT не является вариантом, поскольку слово select также фильтруется. - SQLite по умолчанию не выполняет декодирование URL, шестнадцатеричного кода или юникода. Некоторые препятствия можно обойти, используя простые приемы обхода: - Вводимые пользователем мб внедрены SQL-инъекций. - Пробелы мб обойти с помощью комментариев `/**/`. - `admin` мб обойти с помощью встроенной функции `char()` и оператора `concat (||)`. ![](https://hackmd.io/_uploads/BkTrgDqsh.png) Вот у меня есть таблица о `select-core`, мы мб использовать `values()` вместе `select`. Эта функция values() добавляет значение `admin` в базу данных. ![](https://hackmd.io/_uploads/S1HfuY9i3.png) - Полезная нагрузка: `uid=&upw=&level=0/**/union/**/values(char(97)||char(100)||char(109)||char(105)||char(110))` ![](https://hackmd.io/_uploads/HJK7_Fcs3.png) # Заключение Спасибо за прочтение поста! Увидимся в следующем посте. Пока!