Anon | 00500

Имя пользователя: Anon

Статус: Активен

Регистрация jabber:

Поток: Anon

TG канал: Канал для опретивных оповещений



Закрыть

Назад

SQL-Injection - уязвимость связанная с неправильной обработкой пользовательских данных при составлении SQL запроса. БД сайту нужна для хранения текстовых данных, хотя иногда и картинки хранят в БД (фе...), т.е. твои логин и пароль хранятся в бд, текст этой статьи хранится в БД, да почти все что требует структурированное хранение, простое и быстрое извлечение хранится в БД.

Базы данных имеют свой язык SQL - язык структурированных запросов. Через него сайт общается с БД, получает данные и сохраняет данные. Так вот, при составлении SQL запроса часто трбуется подставить параметр, который передал пользователь. И вот тут начинается рок-н-ролл, когда из-за неправильной фильтрации пользовательских параметров, атакующий может выполнить свой запрос и скомпрометировать базу, а в дальнейшем все приложение и сервер как итог. Давай попробуем.

Открой DVWA, как обычно, и бурп. Для тестировани SQLi поставь уровень сложности Low, так будет проще и перейди в раздел SQL-Injection.

Как видишь поле ввода предлагает ввести тебе User ID, из контекста ID может быть только целым чилом, попробуй ввести 1. Что выдало? Имя и Фамилия пользователя. А теперь взглянем на сорец:

<?php

if( isset( $_REQUEST[ 'Submit' ] ) ) {
    // Get input
    $id = $_REQUEST[ 'id' ];

    // Check database
    $query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
    $result = mysqli_query($GLOBALS["___mysqli_ston"],  $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );

    // Get results
    while( $row = mysqli_fetch_assoc( $result ) ) {
        // Get values
        $first = $row["first_name"];
        $last  = $row["last_name"];

        // Feedback for end user
        echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
    }

    mysqli_close($GLOBALS["___mysqli_ston"]);
}

?> 

"Get input" не требует объяснения, "Check database" тут идет встраивание полученного от пользователя ID в SQL запрос. Да, эта строка SQL запрос к базе данных. И чтобы тебе было понятнее разберемся в основах SQL.

Немного про SQL

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

  • SELECT - extracts data from a database
  • UPDATE - updates data in a database
  • DELETE - deletes data from a database
  • INSERT INTO - inserts new data into a database
  • CREATE DATABASE - creates a new database
  • ALTER DATABASE - modifies a database
  • CREATE TABLE - creates a new table
  • ALTER TABLE - modifies a table
  • DROP TABLE - deletes a table
  • CREATE INDEX - creates an index (search key)
  • DROP INDEX - deletes an index

У SELECT следующий синтаксис

SELECT column_name,column_name2 FROM database.tablename;

вместо перечисления колонок можно поставить * и тогда будет забираться все, а после этого через FROM нужно указать название таблицы, откуда брать эти колонки. При этом если ты в данный момент работаешь с той таблицей откуда берешь данные, то ее имя указывать не обязательно.  Еще раз на тот запрос который в сайте, когда ты передаешь цифру 1 в веб форме и отправляешь форму, то запрос получается таким:

ВЫБЕРИ first_name, last_name ИЗ users ГДЕ user_id = '1';

Да, именно ВЫБЕРИ, потому что запрос SELECT занимается выборкой данных из таблицы. Если ты хочешь выучить SQL, то вот.

В принципе я все это тебе рассказываю чтобы ты понимал откуда профит тут. Переданные тобой из формы данные отправятся напрямую в запрос. И кто сказал что ты не можешь написать там хуй? И да, если ты напишешь "хуй" то так оно в запрос и полетит. Т.е. где здесь ошибка? Правильно, недостаточная, а в данном случае отсутствие, фильтрации пользовательских данных.

Тестируем параметры

От слов к делу. Отправляй цифру в форму, а запрос в интрудер. В интрудуре пометь значение параметра id, тип атаки снайпер и в опциях пейлоада в выпадающем списке найди Fuzzing SQL-Injection. После проведения атаки, ты увидишь, что много пэйлоада прошло, а значит у нас тут SQL инъекция, хотя тут это очевидно. Потыкайся в ответах, там есть места где сервер возвращает нам не один ответ как это было задумано разработчиком, а несколько, также есть места где сервер нам возвращает ошибку синтаксиса SQL.

Вообще, да, изначально для проверки возможности проведения SQL можно было просто отправить не 1, а 1' или 1" в зависимости от того какой тип ковычек использует запрос. Это вызовет в данном случае ошибку синтаксиса SQL о чем веб приложение нас проинформирует. Это как первый  вариант протестировать запрос. Также можно проверить математику, т.е. отправить 2-1 и если сервер вернет данные, такие же как при отправке 1, то можно сказать что тут есть дыра. Еще можно отправить 1 and 2=1, если такой запрос не выполнится, то опять же тут дыра. Ну и еще куча есть вариантов. Мы же не будем мучаться, а будем юзать фаззинг листы и интрудер, для начала.

Еще, обрати внимание на первый скрин, где вместо ковычки я отправил %27 - это ковычка закодированная в URL.

SQLMap

- Хорошо, интрудер показал, что тут есть уязвимость, что дальше?

А дальше мы будем юзать самый лучший сплоит для проведения SQL инъекций - sqlmap. SQLMap - это полноценный интрумент с богатым функционалом. Все что связано с SQLi он может и пробивает до 90%. Итак найди чистый запрос в истории прокси, чистый имею ввиду без ковычек в параметрах. Нажми на поле с запросом ПКМ и внизу "Copy to file".

Вот это должны быть в файле:

GET /dvwa/vulnerabilities/sqli/?id=1&Submit=Submit HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:56.0) Gecko/20100101 Firefox/56.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Cookie: security=low; PHPSESSID=gfcko16d7l48emc2b2fqk9vfq7
Connection: close
Upgrade-Insecure-Requests: 1

И 2 символа перевода каретки (две пустых строки) должны завершать запрос.

Теперь открывай терминал и введи такую команду

sqlmap -r /path/to/request_file

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

Немного о самой сути работы SQLMap`а. В начале он определяет наличие параметров в запросе, затем проводит эвристический анализ ответов сервера, на основании которых SQLMap делает предварительный вывод о том, что параметр уязвим или нет перед инъекцией. После начинается попытка подстановки пэйлоада, на основе анализа. Т.е. бывает такое, что мап говорит мол параметр скорее всего не уязвим, а потом после долгого подробного анализа может его пробить. Ниже представлен список поддерживаемых sqlmap техник проведения атак:

  • UNION query SQL injection. Классический вариант внедрения SQL-кода, когда в уязвимый параметр передается выражение, начинающееся с «UNION ALL SELECT». Эта техника работает, когда веб-приложения напрямую возвращают результат вывода команды SELECT на страницу: с использованием цикла for или похожим способом, так что каждая запись полученной из БД выборки последовательно выводится на страницу. Sqlmap может также эксплуатировать ситуацию, когда возвращается только первая запись из выборки (Partial UNION query SQL injection).
  • Error-based SQL injection. В случае этой атаки сканер заменяет или добавляет в уязвимый параметр синтаксически неправильное выражение, после чего парсит HTTP-ответ (заголовки и тело) в поиске ошибок DBMS, в которых содержалась бы заранее известная инъецированная последовательность символов и где-то «рядом» вывод на интересующий нас подзапрос. Эта техника работает только тогда, когда веб-приложение по каким-то причинам (чаще всего в целях отладки) раскрывает ошибки DBMS.
  • Stacked queries SQL injection. Сканер проверяет, поддерживает ли веб-приложение последовательные запросы, и, если они выполняются, добавляет в уязвимый параметр HTTP-запроса точку с запятой (;) и следом внедряемый SQL-запрос. Этот прием в основном используется для внедрения SQL-команд, отличных от SELECT, например для манипуляции данными (с помощью INSERT или DELETE). Примечательно, что техника потенциально может привести к возможности чтения/записи из файловой системы, а также выполнению команд в ОС. Правда, в зависимости от используемой в качестве бэк-энда системы управления базами данных, а также пользовательских привилегий.
  • Boolean-based blind SQL injection. Реализация так называемой слепой инъекции: данные из БД в «чистом» виде уязвимым веб-приложением нигде не возвращаются. Прием также называется дедуктивным. Sqlmap добавляет в уязвимый параметр HTTP-запроса синтаксически правильно составленное выражение, содержащее подзапрос SELECT (или любую другую команду для получения выборки из базы данных). Для каждого полученного HTTP-ответа выполняется сравнение headers/body страницы с ответом на изначальный запрос — таким образом, утилита может символ за символом определить вывод внедренного SQL-выражения. В качестве альтернативы пользователь может предоставить строку или регулярное выражение для определения «true»-страниц (отсюда и название атаки). Алгоритм бинарного поиска, реализованный в sqlmap для выполнения этой техники, способен извлечь каждый символ вывода максимум семью HTTP-запросами. В том случае, когда вывод состоит не только из обычных символов, сканер подстраивает алгоритм для работы с более широким диапазоном символов (например для unicode’а).
  • Time-based blind SQL injection. Полностью слепая инъекция. Точно так же как и в предыдущем случае, сканер «играет» с уязвимым параметром. Но в этом случае добавляет подзапрос, который приводит к паузе работы DBMS на определенное количество секунд (например, с помощью команд SLEEP() или BENCHMARK()). Используя эту особенность, сканер может посимвольно извлечь данные из БД, сравнивая время ответа на оригинальный запрос и на запрос с внедренным кодом. Здесь также используется алгоритм двоичного поиска. Кроме того, применяется специальный метод для верификации данных, чтобы уменьшить вероятность неправильного извлечения символа из-за нестабильного соединения.

В данном случае мап определил 4 техники проведения атаки, в будущем при работе с этим сайтом он будет выбирать наиболее быструю технику, также были определены: версия ОС, версия веб сервера и версия СУБД.

СУБД - DBMS - Data Base Menegment System - Система Управления Базами Данных

Теперь можно предварительно узнать информацию по СУБД

sqlmap -r dvwa.get --users --current-user --password --hostname --is-dba --current-db --banner
  • --users - получить список пользователей СУБД.
  • --current-user - узнать от какого пользователя сайт работает с СУБД.
  • --password - получить хеши паролей пользователей СУБД.
  • --hostname - имя хоста на котором запущена СУБД.
  • --is-dba - проверить наличие у текущего пользователя привелегированного доступа.
  • --current-db - узнать название текущей БД с которой работает сайт.
  • --banner - вывести банер СУБД.

По каждому хосту мап хранит нужную для работы информацию т.е. дважды тестировать и пытать проникать он не будет, а возьмет результаты из сессии, которые хранятся в "~/.sqlmap". Ну в моем случае я все получил кроме хешей паролей, так как не хватило прав. Ну и хрен с ним, давай глянем на список доступных баз:

sqlmap -r dvwa.get --dbs
available databases [2]:
[*] dvwa
[*] information_schema

Последняя - системная БД, которая хранит информацию о таблицах, базах, пользователях СУБД. Теперь можно глянуть спиок таблиц в базе dvwa, которая, как мы определили является текущей БД, ну это и понятно, она одна.

sqlmap -r dvwa.get -D dvwa --tables

Теперь глянем список колонок в таблице users

sqlmap -r dvwa.get -D dvwa -T users --columns

А теперь только осталось получить данные по интересующим колонкам

sqlmap -r dvwa.get -D dvwa -T users -C user,password --dump

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

Database: dvwa                                                                                                                             
Table: users
[5 entries]
+---------+---------------------------------------------+
| user    | password                                    |
+---------+---------------------------------------------+
| 1337    | 8d3533d75ae2c3966d7e0d4fcc69216b (charley)  |
| admin   | 202cb962ac59075b964b07152d234b70 (123)      |
| gordonb | e99a18c428cb38d5f260853678922e03 (abc123)   |
| pablo   | 0d107d09f5bbe40cade3de5c71e9e9b7 (letmein)  |
| smithy  | 5f4dcc3b5aa765d61d8327deb882cf99 (password) |
+---------+---------------------------------------------+

 

Вот такой вот результат.

Это было интересно и просто.  Для POST запроса тоже самое получится у нас. Интереснее будет перейти сразу на уровень Higth и в раздел "SQL-Injection (Blind)" - это слепая SQL инъекция. Теперь суть такая, что ты меняешь свой ID через форму, которая откроется в отдельном окне и этот id прописывается в куки, а дальше сайт анализирует именно параметр через куки.

И тебе тестировать надо именно гет запрос, который отдает куки на урл, который и проверяет параметр id в бд. POST запрос только устанавливает куки. Сохраняй запрос в файл и запускай sqlmap:

sqlmap -r dvwa.get --banner -p "id" --level=2

Где:

  • -r - файл содержащий запрос.
  • --banner - выведет банер БД.
  • -p - указываем название конкретного параметра, который нужно протестировать.
  • --level=2 - указываем уровень тестирования.

--level - определяет какие параметры будут протестированны.

Из документации.

By default sqlmap tests all GET parameters and POST parameters. When the value of --level is >= 2 it tests also HTTP Cookie header values. When this value is >= 3 it tests also HTTP User-Agent and HTTP Referer header value for SQL injections. It is however possible to manually specify a comma-separated list of parameter(s) that you want sqlmap to test. This will bypass the dependence on value of --level too.

--risk - опредеяет набор тестов которым будут подвергнуты параметры. Более подробно о самих параметрах можно и нужно прочитать в документации.

В общем то описывать дальше нечего, так как sqlmap найдет "boolean-based blind" and "AND/OR time-based blind" SQL-Injection. Да, он еще спросит менять ли куки, которые возвращает ответ сервера, тут стоит отказаться. Поясню, при извлечении данных через слепую инъекцию (когда сервер не выводит текст ошибки, а лишь сигнализирует о ее наличии) желательно указывать кол-во потоков --threads. Максмальное кол-во потоков равно 10 и их не получится использовать при технике "time-based blind", так как тут вытягивание данных зависит от скорости ответа сервера.

WAF

WAF (Web Application Firewall) - Это механизм защиты сервера от инъекционных атак. Он анализирует запросы к серверу по своим фильтрам и может заблокировать его до передачи на сервер. Таким образом атака становится невозможной, даже при наличии уязвимости. SQLMap поддерживает идентификацию использования WAF, а также имеет в своем арсенале кучу дополнений по обходу фаервола. Идентификация waf включается параметром --identify-waf, а обход - через включение тамперов, например --tamper=space2comment, можно через запятую указывать несколько тамперов. Это нужно так как выбираемый тампер зависит от СУБД и WAF.

Тамперы при MSSQL:

apostrophemask, apostrophenullencode, base64encode, between, chardoubleencode, charencode, charunicodeencode, equaltolike, greatest, ifnull2ifisnull, multiplespaces, nonrecursivereplacement, percentage, randomcase, securesphere, space2comment, space2plus, space2randomblank, unionalltounion, unmagicquotes

MySQL

between, charencode, charunicodeencode, equaltolike, greatest, multiplespaces, nonrecursivereplacement, percentage, randomcase, securesphere, sp_password, space2comment, space2dash, space2mssqlblank, space2mysqldash, space2plus, space2randomblank, unionalltounion, unmagicquotes

Список всех скриптов для тампинга пэйлоад

Выбирешь 1-2 тампера и пускаешься в бой.

Резултаты SQLMap

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

/root/.sqlmap/output/127.0.0.1/dump/dvwa

Очень удобно, если в будущем ты опять будешь получить дамп этой таблицы с этого сайта и БД, то старые данные не будут перезаписаны. Также в папке с хостом лежит лог, в котором сохраняются результаты тестирований, например мы не дампили список колонок таблицы users и найти его можно именно в логе, чтобы не получить эти данные повторно, хотя даже если выполнить повторное получение этих колонок, мап вытащит их из файла session.sqlite. И тут есть одно условие, главное чтобы запуск sqlmap был таким же как и при первом получении данных. Ну вот например, мы сначала тестировали гет параметры, а потом пост, в первом случае мы получили колонки, а потом через пост решили попросить, то теперь мап будет опять изимать данные из БД. Потому что запросы разные.

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

Применение в боевых условиях

В боевых условиях при тестировании веб приложений нужно думать о том как не спалиться. Первое что нужно предпринять - это указывать мапу использовать рандомный User-Agent, если этого не сделать, то в запросах будет отдаваться дефолтный юзер агент, содержащий название софта. Второе - использование прокси, sqlmap поддерживает как список прокси, так и указание конкретного прокси, например можно в качестве прокси указать прокси тора.

Если ты по каким то причинам не можешь или не хочешь перехватывать запросы барпом, чтобы просто отправить их в мап, то поступать можно так. Например, ты запустил зевса и насканил себе кучу урлов в файл. Тогда тот подход, на котором мы тренировались не подойдет, так как софт должен упрощать жизнь, а не усложнять ее. И тут нет ничего проще чем просто отдать лог файл, к счастью в логе хостов зевс записыват урлы как ему отдала ПМ (Поисковая Машина), в скульмап.

sqlmap --tamper=space2comment --identify-waf --random-agent -m sqlmap_task.log --batch

Последний параметр включает режим при котором скульмап сам отвечает на свои вопросы, тем самым автоматизируя всю работу. Это конечно интересно, вот только надо понимать, что конверсия при этом снизится. Хотя тут все зависит от твоих предпочтений и целей.

При точечных атаках тебе потребуется указывать URL, Cookie*, Method* для этого также есть соответствующие параметры. Так что теперь переходи к чтению документации. И да, я понимаю, что это скучно.

* Опционально

И еще кое что

Если вдруг нужно сбросить сессию скульмапа, чтобы он что то сделал по новой, то используй параметр --flush-session.

При тестировании можно также указывать какие техники нужно использовать ( --technique=BEUS), по умолчанию используются все техники :

  • B: Boolean-based blind
  • E: Error-based
  • U: Union query-based
  • S: Stacked queries
  • T: Time-based blind
  • Q: Inline queries

Стек запросов это выполнение нескольких запросов следующих друг за другом и разделенные `;`.

SELECT * FROM table_name WHERE name=`admin`; DROP other_table_name --

Этот запрос удалит таблицу `other_table_name` в текущей таблице. Но проблема в том что не все связки поддерживают такие запросы.

ASP.NET | MySQL | Supported
ASP     | MySQL | Not supported
PHP     | MySQL | Not supported
ASP.NET | MSSQL | Supported
ASP     | MSSQL | Supported
PHP     | MSSQL | Supported
ASP.NET | PostgreSQL | Supported
ASP     | PostgreSQL | Supported
PHP     | PostgreSQL | Supported

С чтением и записью файлов существуют другие проблемы. В частности у SQL сервера должны быть права на чтение/запись, нужно знать абсолютный путь и необходимо чтобы команда SQL, выполняющая запись на диск, не была заблокирована. Данные конфигурации встречаются довольно редко, тем не менее они есть и надо это всегда проверять. Чтобы окончательно убедить тебя в том что проверять нужно все, приведу пример в марте 2017-го появилась информация как спамеры слили в общий доступ 700 лямов почт с паролями. Спамеры всего лишь не правильно настроили права на папку с их бекапами и эти данные оказались в общем доступе. Чтобы ты понимал масштабность проблемы, это крупнейшая утечка в истории!