Содержание статьи
- Логирование
- Немного о SQLi
- Неаутентифицированные SQLi
- Аутентифицированные SQLi
- School Setup
- Students
- Users
- Валидация параметров
- Выводы
В этой статье мы с тобой разберем несколько видов SQL-инъекций на боевом примере — приложении openSIS, в коде которого я нашел несколько серьезных проблем. Если ты хочешь научиться обнаруживать потенциальные проблемы в коде на PHP, этот материал должен стать живой иллюстрацией. Особенно она будет полезна новичкам, которые хотят разобраться с темой SQLi. info
Если ты вдруг не в курсе, как вообще работают SQL-инъекции, специально для тебя написана статья «SQL-инъекции. Разбираем на пальцах одну из самых популярных хакерских техник».
openSIS — это бесплатная и открытая информационная система для учебных заведений, доступная для школ и высших учебных заведений. Она разработана и поддерживается компанией Open Solutions for Education.
Я установил это приложение локально, что позволило мне видеть все запросы, отправляемые им в базу данных. Другими словами, тестирование проводилось методом белого ящика: знание кода и структуры данных позволило тщательно изучить, как обрабатывается то, что ввел пользователь, и как формируются SQL-запросы.
Я искал те места в коде, где ввод подставляется в SQL-запрос без должной проверки и чистки (валидации и санитизации). Давай посмотрим, что мне удалось найти.
Статья имеет ознакомительный характер и предназначена для специалистов по безопасности, проводящих тестирование в рамках контракта. Автор и редакция не несут ответственности за любой вред, причиненный с применением изложенной информации. Распространение вредоносных программ, нарушение работы систем и нарушение тайны переписки преследуются по закону.
Логирование
Первым делом нам потребуется настроить логирование запросов к базе данных. То есть нам нужно записывать выполняемые запросы к базе, чтобы потом по ним можно было посмотреть, как программа реагировала на то, что пользователь вводил на сайте. Это поможет нам нагляднее увидеть проблемы и воспользоваться ими.
В MySQL или MariaDB для включения логирования нужно выполнить следующее:
Изменить права на файл или папку и предоставить разрешения пользователю mysql:
chown mysql:mysql /var/log/mysql -R
Открыть файл с настройками MySQL/MariaDB, обычно расположенный в /etc/mysql/my.cnf или /etc/my.cnf.
Найти секцию [mysqld] (если ее нет, добавить самостоятельно).
Добавить или раскомментировать следующие строки для включения логирования запросов:
general_log = 1general_log_file = /var/log/mysql/mysql.log
Перезапустить сервис MySQL/MariaDB, чтобы изменения вступили в силу.
Немного о SQLi
Забегая вперед, скажу, что мы найдем (но не будем эксплуатировать) «слепые» SQL-инъекции. В отличие от других форм SQLi, слепые SQL-инъекции не раскрывают данные напрямую и требуют тонкого подхода к извлечению данных. Слепые SQL-инъекции делятся на две основные категории: на основе булевых значений и на основе времени.
В булевой слепой SQLi мы изменяем SQL-запрос так, чтобы система возвращала булево значение — то есть ответ на то, истинно выражение или ложно. Этот тип атаки использует бинарную природу ответов: содержимое веб‑страницы или код ответа HTTP будет изменяться в зависимости от истинности внедренного запроса. Например, изменение запроса может привести к тому, что какие‑то элементы на веб‑странице будут появляться и исчезать в зависимости от того, истинны ли результаты запроса (условие существует в базе данных) или ложны (его нет).
Временные слепые SQL-инъекции более скрытны. Здесь мы внедряем SQL-команды, которые заставляют базу данных задуматься чуть дольше обычного, и используем это, чтобы вытащить из нее данные. Отсутствие визуальной обратной связи на странице делает эти атаки особенно трудными для обнаружения. Если условие запроса истинно, ответ базы данных намеренно задерживается, и отсутствие задержки означает «ложь». Измеряя время ответа, мы можем определить наличие или отсутствие конкретных данных в базе.
Неаутентифицированные SQLi
При поиске багов в приложении ты должен ориентироваться в первую очередь на уязвимости, которые не требуют аутентификации пользователя, так как они самые опасные. Я нашел две похожие SQL-инъекции в разделе «Студент» в функциях, отвечающих за восстановление имени пользователя и пароля.
Я отправил два запроса: первый, имитируя работу формы Forgot Password, второй — Forgot Username.
Вот в какие SQL-запросы это трансформировалось:
Query SELECT s.* FROM students s,login_authentication la WHERE la.USER_ID=s.STUDENT_ID AND la.USERNAME='aaaaa' AND s.BIRTHDATE='2024-04-25' AND s.STUDENT_ID=XSS AND la.PROFILE_ID=3Query SELECT la.PASSWORD FROM students s,login_authentication la WHERE la.USER_ID=s.STUDENT_ID AND s.BIRTHDATE='2024-04-30' AND la.PROFILE_ID=3 AND s.STUDENT_ID=XSS
Как видишь, s.STUDENT_ID не заключен в кавычки, что делает эту переменную уязвимой для SQL-инъекций. Я могу использовать полезную нагрузку XSS OR 1=1:
tail -f /var/log/mysql/mysql.log | grep -i 'xss'2024-04-27T13:35:15.303711Z 9 Query SELECT s.* FROM students s,login_authentication la WHERE la.USER_ID=s.STUDENT_ID AND la.USERNAME='aaaaa' AND s.BIRTHDATE='2024-04-25' AND s.STUDENT_ID=XSS OR 1=1 AND la.PROFILE_ID=3 2024-04-27T13:35:29.563796Z 10 Query SELECT la.PASSWORD FROM students s,login_authentication la WHERE la.USER_ID=s.STUDENT_ID AND s.BIRTHDATE='2024-04-30' AND la.PROFILE_ID=3 AND s.STUDENT_ID=XSS OR 1=1
Вот как выглядит уязвимый код для восстановления юзернейма. Файл ResetUserInfo.php, строка 395:
$get_stu_info = DBGet(DBQuery('SELECT la.PASSWORD FROM students s,login_authentication la WHERE la.USER_ID=s.STUDENT_ID AND s.BIRTHDATE='' . date('Y-m-d', strtotime($stu_dob)) . '' AND la.PROFILE_ID=3 AND s.STUDENT_ID=' . $username_stn_id . ''));
А вот уязвимый код, который обрабатывает форму восстановления пароля. Файл ResetUserInfo.php, строка 296:
$stu_info = DBGet(DBQuery('SELECT s.* FROM students s,login_authentication la WHERE la.USER_ID=s.STUDENT_ID AND la.USERNAME='' . $uname . '' AND s.BIRTHDATE='' . date('Y-m-d', strtotime($stu_dob)) . '' AND s.STUDENT_ID=' . $password_stn_id . ' AND la.PROFILE_ID=3'));
Отсюда мы можем понять, что если грепнуть по выражению =' . $, то мы, вероятно, получим все параметры, которые не заключены в кавычки.