Перейти к содержимому
← Каталог php SQL Injection

SQL Injection в форме входа

Обход аутентификации через SQL-инъекцию в форме логина.

easyphpPro
Задача
# SQL Injection: обход авторизации через форму входа ## Сценарий Перед вами PHP-приложение интернет-магазина SecureShop. Стек — нативный PHP 8.3 на Apache, для хранения учётных записей и каталога используется SQLite. На странице входа стандартная форма с полями username/password — типовая авторизация, ничего необычного на первый взгляд. Реализация выглядит безобидно, но имеет фундаментальную ошибку, которую часто допускают разработчики, привыкшие к PHP-стилю «склеить строку и отправить»: значения из формы попадают в SQL-запрос **через конкатенацию текста запроса**, без разделения данных и кода. Это даёт атакующему возможность управлять структурой запроса через содержимое полей формы — классический SQL Injection в auth-эндпоинте, входящий в OWASP Top 10 (A03:2021 — Injection) и описанный в CWE-89. В таблице пользователей есть привилегированная учётная запись `admin` с балансом, достаточным для покупки товара «CTF Flag» в каталоге; флаг отображается на странице профиля владельца такого заказа после оформления покупки. Обычный пользователь `demo` с балансом 0 такой покупки совершить не может — только администратор. ## Цели 1. Подтвердите, что в форме входа значения полей попадают в SQL-запрос **как часть SQL-синтаксиса**, а не как данные. Простейший детектор — символ одинарной кавычки в username, ожидаемая реакция — серверная ошибка SQL или нестабильное поведение страницы входа. 2. Обойдите проверку пароля и войдите как `admin`, **не зная** его пароля. Используйте контролируемое вами значение поля username, чтобы изменить структуру SQL-запроса так, чтобы условие проверки пароля было отброшено парсером БД. 3. После входа из-под admin'а добавьте товар «CTF Flag» в корзину, оформите покупку, и заберите CTF-флаг со страницы профиля. Корзина и оформление заказа требуют CSRF-токена — он есть в HTML страницы каталога. ## Почему это типовая ошибка PHP исторически популяризировал «строковые» интерфейсы к БД (старое расширение `mysql_*`, прямой `query()` в PDO), и поколения разработчиков привыкли формировать SQL через конкатенацию переменных в текст запроса. Параметризованные запросы появились в PHP относительно поздно (PDO с PHP 5.1), и до сих пор в legacy-проектах встречается смешение стилей: часть запросов параметризована, часть — нет. SecureShop здесь — реалистичный кейс: основная масса запросов в проекте уже использует prepared statements, и только функция логина была написана «по-быстрому» и осталась уязвимой. ## Уязвимый паттерн Обработчик POST-запроса на форму входа собирает SQL-запрос **строковой конкатенацией**: значения `username` и `password` из тела формы оборачиваются в одинарные кавычки и склеиваются с шаблоном `SELECT ... FROM users WHERE username = '<...>' AND password = '<...>'`. Получившаяся строка отправляется в БД через простой `query()` — без подготовленного шаблона и без отдельной передачи значений как параметров. Парсер БД получает уже готовую строку запроса и не отличает данные пользователя от управляющих конструкций SQL. Достаточно поместить в значение поля специальный символ (одинарную кавычку, комментарий, точку с запятой) — и атакующий перехватывает структуру запроса. ## Точка входа атаки * **Эндпоинт:** `POST /login` с полями `username` и `password`. * **Где появится флаг:** на странице `/profile` после покупки товара «CTF Flag», в виде строки `flag{...}` из переменной окружения `LAB_FLAG`. ## Данные | Параметр | Значение | |----------|----------| | Обычный пользователь | `demo` / `demo` | | Целевая учётная запись | `admin` (пароль не известен — его не нужно угадывать) | | СУБД | SQLite (стандартный SQL-диалект, поддерживает `--` для однострочных комментариев) | | Стоимость товара «CTF Flag» | 9999 — доступно только администратору с соответствующим балансом |
🚧 Сайт в разработке. Полный функционал пока недоступен. Все вопросы — support@hackandfix.ru