Sql инфекции что это
SQL инъекция — это атака, которая задействует динамические операторы SQL , вынося в комментарии определенные части инструкций или добавляя условие, которое всегда будет истинным. Она нацелена на дыры в архитектуре веб-приложений и использует операторы SQL для выполнения вредоносного SQL-кода :
В этой статье мы рассмотрим методы, используемые при SQL-инъекциях и способы защиты веб-приложений от таких атак.
Как работает SQL-инъекциях
Типы атак, которые могут быть выполнены с использованием SQL-инъекции , различаются по типу поражаемых механизмов базы данных. Атака нацеливается на динамические операторы SQL . Динамический оператор — это оператор, который создается во время выполнения на основе параметров из веб-формы или строки запроса URI .
Рассмотрим простое веб-приложение с формой входа. Код HTML-формы приведен ниже:
- Форма принимает адрес электронной почты, а затем пароль отправляется в файл PHP с именем index.php ;
- Сессия хранится в файле cookie . Эта возможность активируется при установке флажка remember_me . Для отправки данных используется метод post . Это означает, что значения не отображаются в URL-адресе .
Предположим, что запрос для проверки идентификатора пользователя на стороне сервера выглядит следующим образом:
- Запрос использует значения массива $ _POST[] напрямую, не санируя его;
- Пароль шифруется с использованием алгоритма MD5 .
Примечание : вам нужно будет написать инструкции SQL :
Шаг 1. Введите этот код в левую панель:
Предположим, что пользователь предоставляет адрес электронной почты [email protected] и 1234 в качестве пароля. Запрос, который должен быть выполнен в базе данных, может выглядеть следующим образом:
Приведенный выше код SQL инъекции примера может быть обойден путем выведения в комментарии части пароля и добавления условия, которое всегда будет истинным. Предположим, что злоумышленник подставляет следующие данные в поле адреса электронной почты:
и xxx в поле пароля.
Сгенерированный динамический оператор будет выглядеть следующим образом:
- [email protected] заканчивается одной кавычкой, которая завершает строку;
- OR 1 = 1 LIMIT 1 — это условие, которое всегда будет истинным, оно ограничивает возвращаемые результаты только одной записью.
0; ‘ AND … — это комментарий SQL , который исключает часть пароля.
Скопируйте приведенный выше запрос и вставьте его в текстовое поле SQL FiddleRun SQL , как показано ниже:
Оно обеспечивает базовую безопасность, такую как санация поля электронной почты. Это означает, что приведенный выше код не может использоваться для обхода данного механизма.
Чтобы обойти его, можно использовать поле пароля. На приведенной ниже диаграмме показаны шаги, которые нужно выполнить:
Предположим, что злоумышленник предоставляет следующие данные:
Шаг 1 : Вводит [email protected] в качестве адреса электронной почты;
Шаг 2 : Вводит xxx’) OR 1 = 1 — ] ;
Он будет направлен в панель администрирования. Сгенерированный запрос будет выглядеть следующим образом:
На приведенной ниже диаграмме показано, как запрос был сгенерирован:
Здесь:
- В запросе предполагается, что используется шифрование md5 ;
- Используется закрывающаяся одиночная кавычка и скобка;
- К оператору добавляется условие, которое всегда будет истинным.
Как правило, злоумышленники для достижения своих целей пытаются применить в атаке с использованием SQL инъекций несколько различных методов.
SQL-инъекции могут нанести гораздо больший ущерб, чем вход в систему в обход механизма авторизации. Некоторые из таких атак могут:
- Выполнить удаление данных;
- Выполнить обновление данных;
- Выполнить добавление данных;
- Выполнить на сервере команды, которые будут загружать и устанавливать вредоносные программы;
- Выполнить экспорт на удаленный сервер злоумышленника ценных данных, таких как реквизиты кредитной карты, электронная почта и пароли.
Приведенный выше список не является полным. Он просто дает представление о том, какую опасность представляют SQL-инъекции .
В приведенном выше примере мы использовали методы ручной атаки. Перед тем, как сделать SQL инъекцию , нужно понимать, что существуют автоматизированные инструменты, которые позволяют выполнять атаки эффективнее и быстрее:
Вот несколько простых правил, которые позволят защититься от атак с использованием SQL-инъекций :
Ввод пользовательских данных не должен быть доверенным . Его всегда нужно санировать, прежде чем данные будут использоваться в динамических операциях SQL.
Хранимые процедуры — они могут инкапсулировать SQL-запросы и обрабатывать все входные данные в качестве параметров.
Подготовленные запросы — сначала создаются запросы, а затем все предоставленные пользовательские данные обрабатываются в качестве параметров. Это не влияет на синтаксис инструкции SQL .
Регулярные выражения — могут быть использованы для обнаружения потенциально вредоносного кода и его удаления перед выполнением операторов SQL .
Права доступа на подключение к базе данных – чтобы защититься от SQL инъекций , учетным записям, которые используются для подключения к базе данных, должны предоставляться только необходимые права доступа. Это поможет ограничить действия, которые SQL-операторы могут выполнять на сервере.
В этом практическом сценарии мы собираемся использовать программу Havij Advanced SQL Injection для сканирования уязвимостей сайта.
Примечание . Ваша антивирусная программа может реагировать на эту программу в силу ее природы. Поэтому необходимо добавить ее в список исключений или приостановить работу антивирусного программного обеспечения:
Упомянутый выше инструмент можно использовать для оценки уязвимости / приложения.
- SQL инъекции — это тип атак, который задействует ненадежные запросы SQL ;
- SQL-инъекции могут использоваться для обхода алгоритмов авторизации, извлечения, вставки, обновления и удаления данных;
- Перечень инструментов для SQL-инъекций включает в себя SQLMap , SQLPing и SQLSmack и другие;
- Продуманная политика безопасности при написании запросов поможет защититься от атаки с использованием SQL-инъекций .
Ставьте лайки, делитесь с друзьями и коллегами, репостите в соц.сетях.
Все программисты читали или по крайней мере слышали о методах взлома безопасности веб-сайта. Или даже столкнулись с этой проблемой. С другой стороны, бесконечна фантазия тех, кто хочет сломать сайт, поэтому все узкие места должны быть хорошо защищены. Вот почему я хотел бы начать серию коротких статей, где будут представлены основные методы и приемы взлома веб-сайтов.
В первой статье я хотел бы описать и разъяснить некоторые общие методы взлома одного из самых уязвимых частей сайта — форм. Я буду подробно останавливаться на том, как использовать эти методы и как предотвратить атаки, а также расскажу о тестировании безопасности.
SQl-инъекция — это такая техника, когда злоумышленник вводит команды SQL в input поле на веб-странице. Этим imput`ом может быть что угодно — текстовое поле в форме, параметры _GET и _POST, cookies и т. д. Этот метод был весьма эффективным до появления фреймворков в мире PHP. Но этот способ взлома может быть по-прежнему опасен, если вы не используете ORM или какие-либо еще расширения для data object. Почему? Из-за способа передачи параметров в SQL запрос.
Давайте начнем с классического примера SQL-statement`а, возвращающего пользователя по его логину и хешу от пароля (страница входа)
Пример 1
Я подставил вопросительные знаки в выражение из-за различных вариаций этого решения. Первый вариант, на мой взгляд, самый уязвимый:
Пример 1а
В этом случае в коде нет проверки на ввод неправильных данных. Значения передаются прямо из формы ввода в SQL запрос. В самом лучшем случае пользователь введет здесь свои логин и пароль. Что случится в худшем случае? Давайте попробуем хакнуть эту форму. Это можно сделать, передав "подготовленные" данные. Попытаемся войти как первый пользователь из базы данных, а в большинстве случаев — это админский аккаунт. Для этого, передадим специальную строку вместо ввода логина:
Первая кавычка может быть и одинарной, поэтому одной попыткой взлома можно не обойтись. В конце стоят точка с запятой и два дефиса, чтобы всё, что идёт после превратилось в комментарий. В результате будет выполнен следующий SQL запрос:
Он вернет первого пользователя из базы данных и, возможно, залогинится под ним в приложении. Хорошим ходом будет добавить LIMIT, чтобы входить под каждым отдельным пользователем. Это единственное, что нужно, чтобы пройти по каждому значению.
В предыдущем примере всё не так уж страшно. Возможности в админской панели управления всегда имеют ограничения и потребуется реально много работы, чтобы поломать сайт. А вот атака через SQL инъекции может привести к куда большим повреждениям системы. Задумайтесь, сколько приложений создаются с главной таблицей 'users' , и что будет, если злоумышленник введет такой код в незащищённую форму:
Таблица 'users' будет удалена. Это одна из причин почаще делать бэкапы баз данных.
Что произойдет, если мы подставим в урл следующий код?
Вероятно, такой запрос вернет нам логин пользователя и. хеш от его пароля. Первая часть запроса `AND 1=0` превращает то, что перед ним в false, соответственно никаких записей не будет получено. А вторая часть запроса вернет данные в виде prepared data. А так как первым параметром идет id, следующим будет логин пользователя и хеш его пароля и еще сколько-то параметров. Существует множество программ, с помощью брутфорса декодирующих такой пароль, как в примере. А так как пользователь может использовать один и тот же пароль для разных сервисов, можно получить доступ и к ним.
И вот что любопытно: от такого способа атаки совершенно невозможно защититься методами вроде `mysql_real_escape_string`, `addslashes` и.т. д. В принципе, нет способа избежать такой атаки, поэтому, если параметры будут передаваться так:
проблемы не исчезнут.
Когда я был новичком в программировании, мне было тяжело работать с кодировками. Я не понимал, в чем между ними различие, зачем использовать UTF-8, когда нужно UTF-16, почему база данных постоянно устанавливает кодировку в latin1. Когда я наконец начал всё это понимать, то обнаружил, что проблем станет меньше, если хранить всё в одном стандарте кодирования. Разбираясь со всем этим, я заметил также и проблемы безопасности, возникающие при преобразовании из одной кодировки в другую.
Проблем, описанных в большинстве предыдущих примеров, можно избежать, используя одинарные кавычки в запросах. Если вы используете addslashes() , атаки через SQL-инъекции, построенные на использовании одинарных кавычек, экранируемых обратным слэшем, потерпят неудачу. Но такая атака может пройти, если просто подставить символ с кодом 0xbf27 , addslashes() преобразует его в символ с кодом 0xbf5c27 – а это вполне валидный символ одинарной кавычки. Другими словами, `뼧` пройдет через addslashes() , а потом маппинг MySQL конвертирует его в два символа 0xbf (¿) и 0x27 (‘).
Этот пример можно хакнуть, передав 뼧 or 1=1; -- в поле логина в форме. Движок SQL сгенерит конечный запрос так:
И вернет первого пользователя из БД.
Как же защитить приложение? Есть куча способов, применение которых не сделает приложение совсем неуязвимым, но хотя бы повысит его защищенность.
Функция addslashes() ненадежна, так как не предусматривает многие случаи взлома. У mysql_real_escape_string нет таких проблем
Это расширение для MySQL умеет работать со связанными параметрами:
Длинный способ подстановки параметров:
Используйте ORM и PDO и связывайте (используйте bind) параметры. Избегайте SQL в коде, если вы видите в коде SQL, значит, с ним что-то не так.
ORM позаботится о безопасности в самых узких местах в коде и о валидации параметров.
Цель этой серии не предоставить полное руководство по взлому сайтов, а обеспечить безопасность приложения и предотвращение атак из любого источника. Я постарался написать эту статью не только для программистов — они должны быть в курсе любых угроз в коде и знать пути, как предотвратить их, но также и для инженеров по качеству — потому, что их работа заключается в том, чтобы отследить и сообщить такие моменты.
Типы SQLi
Существует 5 основных типов SQL инъекций:
- Классическая (In-Band или Union-based). Самая опасная и редко встречающаяся сегодня атака. Позволяет сразу получать любые данные из базы.
- Error-based. Позволяет получать информацию о базе, таблицах и данных на основе выводимого текста ошибки СУБД.
- Boolean-based. Вместо получения всех данных, атакующий может поштучно их перебирать, ориентируясь на простой ответ типа true/false.
- Time-based. Похожа на предыдущую атаку принципом перебора, манипулируя временем отклика базы.
- Out-of-Band. Очень редкие и специфические типы атак, основанные на индивидуальных особенностях баз данных.
Далее мы разберем их детальней.
Уязвимые точки
Уязвимые точки для атаки находятся в местах, где формируется запрос к базе: форма аутентификации, поисковая строка, каталог, REST-запросы и непосредственно URL.
Защита от SQLi
Для каждого сервера и фреймворка есть свои тонкости и лучшие практики, но суть всегда одинакова.
Нельзя вставлять данные в запрос напрямую. Всегда обрабатывайте ввод отдельно и формируйте запрос исключительно из безопасных значений.
Создавайте белые списки: их значительно труднее обойти, чем черные. Все названия таблиц, полей и баз должны быть заданы конкретными значениями в вашей программе. Это касается и операторов.
Естественно, не забывайте про ограничение прав доступа к базе.
Тем не менее, кибербезопасность – это тот случай, когда понимание принципов нападения – лучший способ защиты.
Классические атаки
Самый простой пример критически уязвимого для SQLi кода выглядит следующим образом:
Представляя такой антипример, можно понять принцип действия атак, которые мы рассмотрим ниже.
Использование однострочных комментариев позволяет игнорировать часть запроса, идущую после вашей инъекции. Например, ввод в уязвимое поле Username запроса admin'-- позволит зайти на ресурс под администратором, потому что поверка пароля будет закомментирована. Конечно, сейчас такой тип уязвимости встречается очень редко, но помнить о ней стоит.
Многострочные комментарии могут справится с проверкой или определить тип базы данных. Например, подобные запросы обойдут примитивный текстовый анализ:
А некоторые особые комментарии позволят определить тип базы данных в целях дальнейшей эксплуатации уязвимостей:
Существует ряд более продвинутых способов обходить черные списки. Например, против фильтра кавычек можно использовать конкатенацию строк:
В MySQL для обхода сложных паттернов можно представлять строки в шеснадцатиричном виде, с помощью функции HEX() или вводить их посимвольно:
Есть стандартный словарь, содержащий в себе основные запросы, для обхода уязвимой формы аутентификации. Впервые его опубликовали лет 10 назад и регулярно дополняют. Не забудьте прогнать через него формы регистрации на своем сайте:
UNION это SQL-команда, позволяющая вертикально комбинировать данные из разных таблиц в одну. Это одна из самых популярных и опасных классических инъекций.
Если целевой сервис работает на SQL Server и ASP/PHP, либо на PostgreSQL и PHP, можно использовать простой знак ';' для последовательного вызова вредоносных запросов:
Конкретных примеров и нюансов довольно много, не будем перечислять все. Главное, помните, что комбинируя эти приёмы и различные специфические функции, атакующий может получить полный доступ к базе и даже командной строке.
Error-Based
Чтобы побороть этот тип атак, достаточно запретить вывод ошибок на проде. Тем не менее, давайте на примере разберем, чем вам может грозить игнорирование этой меры.
Последовательное выполнение следующих запросов к SQL Server, позволит определить в тексте ошибки названия столбцов:
Слепые инъекции
В более-менее хорошо сделанном приложении атакующий не увидите ни ошибок, ни результата UNION-атаки. Тут приходит очередь действовать вслепую.
Атаки с использованием IF и WHERE – основа слепого метода. Они являются одной из причин, почему используемые вами операторы должны быть закодированы в программе, а не генерироваться абы как. Синтаксис для разных баз будет отличаться:
Если атакующий все же может получить информацию о наличии или отсутствии ошибки из HTTP-статуса, в сервисе имеется уязвимость к обычной слепой атаке. Рассмотрим запрос, который позволит нам при помощи алгоритма бинарного поиска посимвольно определить название первой таблицы и в дальнейшем всех данных:
Если атакующий не наблюдает никаких отличий в ответах сервера, остается полностью слепая атака. Примером будет использование функций SLEEP или WAIT FOR DALAY:
Конечно, реальные примеры будут выглядеть примерно как boolean-based, только true и false атакующий будет отличать по времени отклика. Недостатки такого метода очевидны. Если выбрать слишком маленькую задержку, будет сильное влияние сторонних факторов типа пинга. Если слишком большую – атака займет очень много времени и её, скорее всего, остановят.
Конечно, по SQLi можно писать целые книги, но мы постарались объяснить ключевые принципы с примерами.
SQL Injection достаточно хорошая возможность для хакера получить
доступ к серверу. И при небольшом усилии, он
все-таки его получает 🙂
Coder inside
В наше время работа с базами данных поддерживается
практически всеми языками программирования, к таким можно отнести BASIC, C++, Java, PERL, PHP, Assembler и даже JavaScript! А называются эти программы никак иначе как СУБД - системы управления базами данных. Зачастую базы данных применяются для решения финансовых задач,
бухгалтерии, организации кадров, но свое применение они нашли и в Интернете.
Базы данных часто используются для написания WEB-приложений. Их использование наиболее уместно для хранения пользовательских регистрационных данных, идентификаторов сессий, организации поиска, а также других задач требующих обработки большего
количества данных. Для обращения к БД используются серверные технологии: PHP, PERL, ASP, и т.д. Именно тут и начинается самое интересное. Когда на сервере
установлены все патчи, а брандмауэр блокирует все порты кроме 80-ого или когда требуется аутентификация для доступа к некоторым данным, для взлома хакер может использовать SQL Injection. Суть данной атаки заключается в использовании ошибки на стыке WEB технологий и SQL. Дело в том, что многие web страницы для обработки пользовательских данных, формируют специальный SQL запрос к БД. Неосторожное использование данной методики может привести к довольно интересным результатам.
SQL Injection
Для пояснения атаки представим себе, что ты зашел на сайт чтобы скачать одну очень важную тулзу и с ужасом замечаешь, что сделать это может только зарегистрированный пользователь, а регистрация, конечно же, стоит денег 🙂 Последние заработанные отдавать не хочется, а без программы никак! Самое время вспомнить о том как
обращаться к базам данных SQL. Например, проверка логина и пароля, на PHP может иметь следующий вид:
$result=mysql_db_query($db,"SELECT * FROM $table WHERE user='$login' AND
pass='$password'");
$num_rows=mysql_num_rows($result);
mysql_close($link);
if ($num_rows!=0)
<
// AUTHENTICATION OK
>
else
<
// AUTHENTICATION ERROR
>
SELECT * FROM users WHERE login='user' AND
password='31337'
Это значит примерно следующее: верни мне все записи из базы данных users у которых логин "user", а пароль "31337". Если существует такая запись, значит пользователь зарегистрирован, ну а если нет, то нет. Но при определенных обстоятельствах все можно исправить. Имеется ввиду ситуация, когда приложение не проверяет содержимое передаваемых данных или проверяет не полностью, на наличие SQL инструкций. В данном примере сверяются два поля login и password, но если в качестве пароля указать "31337' AND email='[email protected]"(без двойных кавычек), то запрос получится уже немного другим:
SELECT * FROM users WHERE login='user' AND password='31337' AND
email='[email protected]'
И в случае существования поля email это условие также будет проверено. Если вспомнить основы булевой алгебры, то приходит в голову что кроме операции "и" существует и "или", а поскольку их использование поддерживается SQL, можно выше
описанным способом добавить условие которое всегда возвращает истину. Для осуществления данного, необходимо в качестве логина указать "user' OR 1=1--", в таком случае запрос примет вид:
SELECT * FROM users WHERE login='user' OR 1=1--' AND
password='31337'
Для начала следует знать, что "--" означает конец запроса, и все после "--"
обрабатываться не будет! Получается, словно мы сделали запрос:
SELECT * FROM users WHERE login='user' OR 1=1
Как вы видите мы добавили условие "1=1", значит критерием проверки будет "если логин 'user' или 1=1", но ведь 1 всегда равно 1 (исключением может быть только арифметика Дани Шеповалова :)). Чтобы проверить наши подозрения
забиваем в адресной строке "http://www.server.com?login=user or 1=1--&password=31337". Это приводит к тому, что не играет роли какой именно логин мы указали, а
тем более пароль! И мы в матри. ой, в системе и можем спокойно качать то что нам необходимо.
Но это все в теории. На практике нам неизвестно каким образом формируется запрос, какие данные передаются и в какой последовательности. Поэтому необходимо указывать "user' OR 1=1--" для всех полей. Также следует проверить форму отправки на наличие скрытых полей. В HTML они описываются как " ". Если таковые существуют, сохраните страницу и поменяйте значения данных полей. Значения содержащиеся в них часто забывают проверять на наличие SQL инструкций. Но чтобы все заработало следует в форме (тэг "FORM") для параметра "ACTION" указать полный путь к скрипту, что обрабатывает данный запрос.
Но не всегда также известно как сформирован запрос,
прошлый пример можно было сформировать и следующими способами:
SELECT * FROM users WHERE (login='user' AND password='31337')
SELECT * FROM users WHERE login="user" AND password="31337"
SELECT * FROM users WHERE login=user AND password=31337
В таком случае можно попробовать следующие варианты:
Все зависит от предназначения скрипта, и от программиста. Поскольку каждому человеку свойственно все делать по своему, то вполне возможно, что программист выберет не самый простой вариант. Поэтому не следует сразу
сдаваться, если вы получите отказ. Необходимо
испробовать как можно большее количество вариантов.
Password detection
Обходить авторизацию неплохо, но очень часто дырка которую вы используете закрывается, и все что было для вас доступно теряется.
Этого и следовало ожидать, если программист не дурак он
со временем прикроет все лазейки. От таких ситуаций можно легко избавится заранее позаботившись об этом. Правильным решением может стать угадывание пароля посредством
анализа результатов аутентификации. Для начала пробуем угадать пароль, для этого введем место него:
Если нам ответят, что авторизация пройдена, значит пароль
начинается не на букву "а", а на какую-то из следующих по списку. Двигаемся дальше и подставляем
место "a", следующие "b", "c", "d", "e". и т.д. пока нам не ответят, что пароль не правильный. Пускай этот процесс остановился на символе "x", в таком случае создаются два варианта развития ситуации, пароль найден или же пароль начитается на этот символ. Чтобы проверить первый вариант пишем место пароля:
и если пароль принят и тебя впустили, значит ты угадал пароль! Ну а нет, тогда следует подбирать уже второй символ,
точно так же, с начала. Для двух символов проверять
нужно так же. В конце концов, ты получишь пароль, а логин ищешь тем самым путем 🙂
В случае, если найденные пароль и логин тебя не устраивают, можешь отыскать и другие. Для этого необходимо начать проверку с последнего символа найденного пароля. Так, если пароль был "xxx" проверять необходимо существование пароля
"xxy":
чтобы не упустить не один вариант!
MS SQL Server
MS SQL Server вообще находка, если упущена необходимая фильтрация. Используя уязвимость SQL Injection можно исполнять
команды на удаленном сервере с помощью exec master..xp_cmdshell. Но чтобы использовать эту конструкцию
необходимо завершить операцию "SELECT". В SQL инструкции разделяются точкой с запятой. Поэтому подключится к некоторому IP по Telnet'у, необходимо место пароля/логина набрать:
'; exec master..xp_cmdshell 'telnet 192.168.0.1' --
У MS SQL Server есть, еще несколько интересных особенностей, позволяющих узнать логины и пароли хранящиеся в базе данных. Для этого вывод об ошибках перенаправляется на произвольный сервер и посредствам их
анализа можно узнать название таблицы, полей и их типов. После чего можно запросом
' UNION SELECT TOP 1 login FROM users--
(login имя поля содержащего логин, а users - имя таблицы,
полуученые в процессе анализа ошибок).
Ответ может быть следующим:
Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value 'admin' to a column of data type int.
/default.asp, line 27
Теперь мы знаем, что есть пользователь с именем "admin". Теперь мы можем получить его пароль:
' UNION SELECT TOP 1 password FROM users where login='admin'--
Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value 'xxx' to a column of data type int.
/tedault.asp, line 27
Теперь нам известно, что есть пользователь "admin" с паролем "xxx". Этим можно смело
воспользоваться и залогинится в систему 😉
Но для работы с SQL существует еще много других функций,
при работе с базой данных можно также удалять данные, модифицировать, вставлять свои и даже манипулировать файлами и работать с реестром.
В общем, SQL Server - рулит 🙂
Защита
Но этого всего естественно можно избежать. Для этого можно
воспользоваться фильтрами,
предоставляемыми производителями. Можно найти свои решения, например заменять все одинарные
кавычки двойными (если для SQL запроса мы пользуетесь одинарными), или наоборот. Можно разрешить только использование букв и с@баки, в случае если требуется ввести
электронный адрес. А еще в перле есть удивительная
функция 🙂 quote() в модуле DBI::DBD, которая успешно делает ваш запрос безопасным по отношению к SQL. Решений много, необходимо просто ими
воспользоваться. Иначе зачем тогда все это.
Этичный хакинг и тестирование на проникновение, информационная безопасность
SQL-инъекция для новичков
SQL-инъекция – это опасная уязвимость, которая возникает из-за недостаточной фильтрации вводимых пользователем данных, что позволяет модифицировать запросы к базам данных. Результатом эксплуатации SQL-инъекции является получение доступа к данным, к которым в обычных условиях у пользователя не было бы доступа.
Обычно SQLi находят в веб-приложениях. Но на самом деле, SQL-инъекции могут быть подвержены любые программы, использующие разные базы данных (не только MySQL/MariaDB).
В качестве примера, рассмотрим приложение, которое обращается к базе данных со следующим запросом:
Запрос похож на естественный язык (английский), и его значение довольно просто интерпретировать:
Выбрать (SELECT) поля `name`, `status`, `books` из (FROM) таблицы `members` где (WHERE) значение поля name равно величине Demo (name = 'Demo') и (AND) значение поля password равно величине 111 (password ='111').
Этот запрос вызывает обход таблицы, в результате которого делается сравнение с каждой строкой, и если условие name = 'Demo' AND password ='111' является для какой-либо строки истиной, то она попадает в результаты. В данном случае, результаты будут только если и введённое имя пользователя, и пароль в точности совпадают с теми, которые хранятся в таблице.
Предположим, что вместо Demo пользователь ввёл такую строку:
Тогда запрос к базе данных будет иметь вид:
Поскольку в комментарии осталась закрывающая кавычка, то она также была введена с именем пользователя, чтобы не сломать синтаксис и не вызвать ошибку, в результате, фактически, к базе данных делался следующий запрос:
В нём была нарушена логика работы программы, заложенная разработчиками. Т.е. теперь поиск в таблице производится только по имени. И если имя совпало, то строка попадает в результаты независимо от введённого пароля. Это и есть пример эксплуатации SQL-инъекции. В реальной ситуации, такая ошибка может быть использована на веб-сайте для входа под учётной записью администратора, для которой достаточно знать только имя, а пароль становится ненужным.
Кроме обхода аутентификации, SQL-инъекция используется для извлечения информации из баз данных, вызова отказа в обслуживании (DoS), эксплуатацию других уязвимостей (вроде XSS) и т.п.
Эксплуатации SQL-инъекции
Каждый раз с любым приложением, где бы не эксплуатировалась SQL-инъекция, используются следующие три базовых правила внедрения:
- Балансировка
- Внедрение
- Комментирование
Балансировка заключается в том, что количество открывающих и закрывающих кавычек и скобок должно быть одинаковым, чтобы не вызвать ошибку синтаксиса. При исследовании ошибки нужно определить, используются, и если используются, то какие кавычки и скобки.
Внедрение заключается в дополнении запроса в зависимости от информации, которую мы хотим получить.
Комментирование позволяет отсечь заключительную часть запроса, чтобы она не нарушала синтаксис.
Комментарии в MySQL начинаются с символов:
можно было бы ввести
Обратите внимание, что после двойной черты обязательно нужен пробел, а после # пробел необязателен.
Можно продолжить менять логику запроса, если в качестве имени пользователя вставить:
то получится запрос
Уберём закомментированную часть:
Мы используем логическое ИЛИ (OR). Логическое ИЛИ возвращает true (истину) если хотя бы одно из выражений является истиной. В данном случае второе выражение 1 всегда является истинной. Следовательно, в результаты попадут вообще все записи таблицы. В реальном веб-приложении можно достичь результата, когда будут выведены данные всех пользователей, несмотря на то, что атакующий не знал ни их логины, ни пароли.
В нашем примере после введённого значения Demo мы ставили одинарную кавычку ('), чтобы запрос оставался правильным с точки зрения синтаксиса. Запрос может быть написан по-разному, например, все следующие формы возвращают одинаковый результат.
Для запросов с цифрой:
Для запросов со строкой:
В зависимости от того, как составлен запрос, нужно использовать соответствующие символы парные закрывающие символы, чтобы не происходило нарушения синтаксиса. Например, если бы запрос был записан так (в нём вместо одинарных кавычек, используются двойные):
то имя пользователя
не возымело бы действия и не вызвало бы ошибку. Для обозначения конца введённого имени нужно использовать закрывающую двойную кавычку, т.е.:
Для такого запроса (используются одинарные кавычки и круглые скобки):
нужно также закрывать круглые скобки, т.е. для эксплуатации SQL-инъекции нужно ввести что-то вроде
Главными признаками наличия SQL-инъекции является вывод ошибки или отсутствие вывода при вводе одинарной или двойной кавычки. Эти символы могут вызвать ошибку и в самом приложении, поэтому чтобы быть уверенным, что вы имеете дело именно с SQL-инъекцией, а не с другой ошибкой, нужно изучить выводимое сообщение.
Далее перечень СУБД и вариантов выводимых ими ошибок:
Стиль ошибок MySQL:
Ошибка в MSSQL ASPX:
Ошибка в MSAccess (Apache PHP):
Ошибка в MSAccesss (IIS ASP):
Ошибка в Oracle:
Ошибка в PostgreSQL:
Ошибка в MS SQL Server:
Информация об СУБД также используется определения, какие символы или последовательности символов можно использовать в качестве комментариев.
Практический пример простой SQL-инъекции
Для тренировки я буду использовать bWAPP (по ссылке описание и процесс установки).
Далее выполним ряд тестов.
Это говорит о том, что одинарные кавычки не фильтруются и что для обрамления введённых строк не используются двойные кавычки.
Т.е. ничего не найдено, это говорит о том, что двойные кавычки также не фильтруются (иначе был бы найден фильм по запросу Iron Man). Также это говорит о том, что для обрамления введённых строк используются одинарные кавычки.
Исходя из полученной информации, формируем строку для вывода всех записей таблицы:
Определение количества столбцов таблицы с помощью ORDER BY
Для создания более сложных команд инъекции нужно знать, сколько в таблице столбцов.
ORDER BY задаёт сортировку полученных из таблицы данных. Можно задавать сортировку по имени столбца, а можно по его номеру. Причём, если столбца с таким номером нет, то будет показана ошибка.
Последовательно пробуем следующие строки (AND 0 используется для подавления лишнего вывода):
получен следующий результат:
Это означает, что восьмой столбец отсутствует в таблице, т.е. в таблице всего семь столбцов.
Другой способ нахождения количества столбцов – с помощью того же UNION. Лесенкой прибавляем количество столбцов:
Все они будут вызывать одну и туже ошибку:
Делайте так пока не исчезнет сообщение об ошибке.
Объединение запросов с UNION SELECT
UNION позволяет объединять результаты в один от нескольких выражений SELECT.
Конструируем наш запрос с UNION:
Как я сказал, количество полей должно быть в обоих SELECT одинаковое, а вот что в этих полях — не очень важно. Можно, например, прописать просто цифры — и именно они и будут выведены. Можно прописать NULL – тогда вместо поля ничего не будет выведено.
Обратите внимание, что содержимое некоторых полей UNION SELECT 2,3,4,5 выводится на экран. Вместо цифр можно задать функции.
Что писать в SELECT
Есть некоторые функции и переменные, которые можно писать непосредственно в UNION:
Переменная / Функция | Вывод |
---|---|
@@hostname | Текущее имя хоста |
@@tmpdir | Директория для временных файлов |
@@datadir | Директория с базами данных |
@@version | Версия БД |
@@basedir | Базовая директория |
user() | Текущий пользователь |
database() | Текущая база данных |
version() | Версия |
schema() | Текущая база данных |
UUID() | Ключ системного UUID |
current_user() | Текущий пользователь |
current_user | Текущий пользователь |
system_user() | Текущий системный пользователь |
session_user() | Сессионный пользователь |
@@GLOBAL.have_symlink | Проверка, включены или отключены симлинки |
@@GLOBAL.have_ssl | Проверка, имеется SSL или нет |
Ввод для получения имени базы данных:
База данных INFORMATION_SCHEMA
В списке баз данных MySQL / MariaDB всегда присутствует INFORMATION_SCHEMA. Это служебная БД, которая обеспечивает доступ к метаданным баз данных, информации о сервере MySQL. Проще говоря, она содержит информацию о всех других базах данных, которые поддерживает MySQL / MariaDB сервер. Эта информация включает имена баз данных и таблиц.
Например, следующий запрос выведет имена всех баз данных, присутствующих на сервере:
- SELECT и FROM – уже знакомые элементы языка запросов к базам данных;
- SCHEMA_NAME – имя запрашиваемого столбца;
- INFORMATION_SCHEMA – имя базы данных, к которой делается запрос;
- SCHEMATA – имя таблицы, в которой ищется запрашиваемый столбец.
Получение списка всех баз данных на сервере через SQL-инъекцию
Используя UNION, мы можем сделать запрос к базе данных INFORMATION_SCHEMA. Например, чтобы вывести содержимое поля SCHEMA_NAME (имена присутствующих баз данных на сервере), можно сделать примерно следующий ввод:
Иногда скрипт веб-приложения, подверженный SQL-инъекции, выводит только по одной записи. В нашем примере это не так, но если бы, например, ввод
выводил только по одной записи, то для того, чтобы посмотреть все таблицы, можно было бы использовать LIMIT. Например, для первой строки:
Для второй строки:
Для третьей строки:
Для четвёртой строки:
Можно задействовать более сложный синтаксис с использованием WHERE и функций. Например, следующий ввод приведёт к показу имён таблиц текущей базы данных:
Получив имена таблиц баз данных, можно продолжить далее и получить имена столбцов:
Где вместо tablenamehere нужно подставлять имя таблицы.
Например, нами получены следующий имена присутствующих в базе данных таблиц:
Тогда для получения имён столбцов в таблице blog нужно сформировать запрос
Применительно к нашей уязвимости получаем ввод:
Здесь также можно применять LIMIT.
Извлечение данных из таблицы с помощью SQL-инъекции
Теперь, когда мы знаем имя базы данных, имя таблицы и имя поля, мы можем извлечь данные из произвольной колонки. Например, ввод:
Например, следующий ввод для нашей уязвимости означает извлечь содержимое колонки login из таблицы users из текущей БД:
Заключение по первой части
В первой части были рассмотрены азы SQL-инъекции. В последующих частях будут рассмотрены различные виды SQLi и примеры эксплуатации в различных условиях. Если у вас возникли затруднения с пониманием этого материала, то рекомендуется начать с изучением языка запросов к базе данных. Если вопросы остались, то пишите их в комментариях.
Читайте также: