# Анализирование
Сначала мы просмотрим веб-сайт, на веб-сайте есть такая форма входа

Здесь у на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 (||)`.

Вот у меня есть таблица о `select-core`, мы мб использовать `values()` вместе `select`. Эта функция values() добавляет значение `admin` в базу данных.

- Полезная нагрузка:
`uid=&upw=&level=0/**/union/**/values(char(97)||char(100)||char(109)||char(105)||char(110))`

# Заключение
Спасибо за прочтение поста! Увидимся в следующем посте. Пока!