В этой статье мы рассмотрим, как DataArmor противодействует такому распространенному инструменту хакеров, как SQL‑инъекция, — внедрению в текст запроса к базе данных вредоносного SQL-кода.

Sqlmap

Хотя существует достаточно большое количество разнообразных инструментов для автоматического тестирования защищённости веб-приложений, в рамках данной статьи речь пойдёт об утилите Sqlmap. Эта программа написана на языке Python, она бесплатна, имеет открытый исходный код, достаточно проста в использовании благодаря консольному интерфейсу. Согласно официальному описанию, при анализе уязвимостей Sqlmap использует следующие методы SQL-инъекции:

Boolean-based blind (Слепая инъекция)

Sqlmap добавляет к уязвимому параметру HTTP-запроса синтаксически корректное выражение, содержащее подзапрос SELECT или другую команду для вывода информации из базы данных. Затем проводится сравнение каждого полученного HTTP-ответа с ответом на изначальный запрос. В итоге утилита «извлекает» вывод внедрённого SQL-выражения символ за символом.

Time-based blind (Абсолютно слепая SQL‑инъекция)

Sqlmap добавляет к уязвимому параметру синтаксически корректное выражение, содержащее запрос, устанавливающий временную задержку в работе СУБД. Затем утилита проводит сравнение между временем ответа на оригинальный запрос и временем ответа на «инфицированный» запрос и извлекает вывод по одному символу.

Error based

Это вариант реализации слепой инъекции, основанный на провокации ошибки СУБД. Sqlmap внедряет в уязвимый параметр синтаксически некорректное выражение, вызывающее ошибку. Полученный от БД ответ подвергается синтаксическому анализу для поиска сообщений об ошибке, содержащих цепочки символов, внедрённых в процессе SQL-инъекции. Далее Sqlmap по коду инъекции обнаруживает вывод подзапроса.
Нужно отметить, что этот метод работает только в том случае, если веб-приложение настроено на отображение ошибок СУБД.

UNION query-based

Sqlmap добавляет к уязвимому параметру синтаксически корректное SQL-выражение, начинающееся с «UNION ALL SELECT». Этот метод применяется в случаях, когда веб-приложения напрямую возвращают результат вывода на страницу (например, при помощи цикла For) с выводом каждой записи из выборки на страницу.
Sqlmap также способна работать с т. н. «частичными» UNION-уязвимостями, которые возникают в тех случаях, когда цикл не задействуется, а на страницу выводится лишь первая запись выборки.

Stacked queries (piggy backing)

Если целевое веб-приложение поддерживает последовательные запросы, Sqlmap добавляет к уязвимому параметру HTTP-запроса точку с запятой (;), за которой следует внедряемый SQL-код. Обычно этот метод используется для инъекции операторов, отличных от SELECT (например, DDL и DML-операторов). Теоретически, данный метод SQL-инъекции­ позволяет производить чтение/запись из файловой системы и выполнение команд в операционной системе (эти возможности зависят от бэк-энда СУБД и пользовательских привилегий).

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

Подготовка к тестам

Объектом SQL-инъекции в нашем эксперименте послужит простейший веб-сервер, написанный на языке Python. Задачей данного сервера является вывод пользователю информации по условиям, которые передаются в качестве параметров через URL. Сохраним код сервера в файле «webserv_inj.py«: from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib.parse import urlparse
import urllib.request
import pyodbc
import re
global dbconnection
global dbcursor

class InjectedServer(BaseHTTPRequestHandler):
    def do_GET(self):
    self.send_response(200)
   self.send_header("Content-type", "text/html charset=windows-1251")
    self.end_headers()

    o = urlparse(self.path)
    papams = urllib.request.unquote(o.query)
    m = re.search("id=(?P[^;]+);name=(?P[^;]+)",papams )

    id = m.group("id")
    name = m.group("name")

    dbconnection = pyodbc.connect("Driver=PostgreSQL ODBC Driver(ANSI);
Server=localhost;Port=54321;Database=test_db;Uid=postgres;Pwd=admin;UseServerSidePrepare=1")
    dbcursor = dbconnection.cursor()
    queryStr = "select * from injected_table where id = " + id + " and name = '" + name + "' order by id"
    dbcursor.execute(queryStr)
    result = dbcursor.fetchall()
    for row in result:
    self.wfile.write(bytes(str(row[0]) , "utf-8"))
    self.wfile.write(bytes(str(row[1]) , "utf-8"))
    self.wfile.write(bytes(str(row[2]) , "utf-8"))
myServer = HTTPServer(("127.0.0.1", 6589), InjectedServer)

try:
    myServer.serve_forever()
except KeyboardInterrupt:
    pass
myServer.server_close()
В процессе тестирования мы попытаемся взломать веб-сервер, чтобы получить информацию из базы данных PostgreSQL. Создадим в базе данных новую таблицу «injected_table» и внесём в неё две записи: CREATE TABLE injected_table
(
id integer,
name character varying(200),
surname character varying(200)
)

INSERT INTO injected_table VALUES (1, Bob, Martin);
INSERT INTO injected_table VALUES (2, Denis, Morgan);
injected_table

Так выглядит готовая таблица в PGAdmin

Запускаем наш сервер, выполнив в командной строке следующую команду: python webserv_inj.py Убедимся, что всё работает, передав серверу через веб-браузер следующий запрос: http://127.0.0.1:6589/?id=2;name=Denis
Веб-сервер выведет запись из базы данных, значение в колонке ID которой равно "2", а в колонке name — равно "Denis"

Веб-сервер выведет запись из базы данных, значение в колонке ID которой равно «2», а в колонке name — равно «Denis»

Тестирование веб-сервера на наличие уязвимостей

Теперь мы можем протестировать наш веб сервер на наличие в нём уязвимостей. Для этого запустим в командной строке Sqlmap: python.exe sqlmap.py -u http://127.0.0.1:6589/?id=2;name=Denis По окончании тестирования заглянем в лог-файл программы (он создаётся автоматически и хранится в папке «output»): sqlmap identified the following injection point(s) with a total of 50 HTTP(s) requests:
---
Parameter: id (GET)
    Type: boolean-based blind
    Title: AND boolean-based blind - WHERE or HAVING clause
    Payload: id=2;name=Denis' AND 8150=8150 AND 'lsHq'='lsHq

    Type: AND/OR time-based blind
    Title: PostgreSQL > 8.1 AND time-based blind
    Payload: id=2;name=Denis' AND 9061=(SELECT 9061 FROM PG_SLEEP(5)) AND 'TLxE'='TLxE
    Type: UNION query
    Title: Generic UNION query (NULL) - 3 columns
    Payload: id=2;name=Denis' UNION ALL SELECT NULL,NULL,(CHR(113)||CHR(112)||CHR(120)||CHR(120)||CHR(113))||
(CHR(88)||CHR(109)||CHR(66)||CHR(103)||CHR(114)||CHR(69)||CHR(83)||CHR(119)||CHR(113)||CHR(98)||CHR(110)||
CHR(73)||CHR(90)||CHR(83)||CHR(90)||CHR(121)||CHR(113)||CHR(102)||CHR(85)||CHR(117)||CHR(107)||CHR(72)||
CHR(78)||CHR(101)||CHR(79)||CHR(90)||CHR(112)||CHR(120)||CHR(74)||CHR(106)||CHR(114)||CHR(105)||CHR(85)||
CHR(84)||CHR(71)||CHR(104)||CHR(71)||CHR(89)||CHR(75)||CHR(111))||(CHR(113)||CHR(122)||CHR(107)||CHR(122)||CHR(113))-- -
---
back-end DBMS: PostgreSQL
Как можно видеть, утилита корректно определила версию СУБД (PostgreSQL), обозначила параметр «ID» как уязвимый, а также предоставила три варианта SQL-выражений для проведения SQL-инъекции (строки «Payload»).

Теперь пришло время основного теста, в процессе которого мы проверим, насколько эффективно DataArmor сможет защитить базу данных от SQL-инъекций.
Настройки правила защиты от SQL-инъекций DataArmor

Настройки правила защиты от SQL-инъекций DataArmor

Создадим правило защиты от SQL-инъекций. Работа с правилами описана в Руководстве пользователя DataArmor, поэтому здесь мы на этом процессе останавливаться не будем. Также удалим файлы, содержащие сведения о ранее обнаруженных уязвимостях, из папки «output» Sqlmap.

Вновь запустим проверку веб-сервера при помощи Sqlmap и по окончании тестирования ознакомимся с логом:
Лог Sqlmap. Обратите внимание, что в данном случае утилита не смогла внести информацию в лог-файл из-за отсутствия уязвимостей в коде веб-сервера

Лог Sqlmap. Обратите внимание, что в данном случае утилита не смогла внести информацию в лог-файл из-за отсутствия уязвимостей в коде веб-сервера

Судя по записям в логе, Sqlmap определила, что все проверенные параметры являются неуязвимыми для SQL-инъекции (all tested parameters appear to be not injectable). В том числе, и параметр «ID«, который был обозначен как уязвимый в первом тесте и мог использоваться для проведения SQL-инъекции.

Вывод

Хотя межсетевой экран DataArmor обладает достаточно высокой эффективностью, он не способен обнаружить и заблокировать все возможные варианты SQL-инъекции. Защита от атак подобного рода должна быть многоуровневой и включать в себя следующие мероприятия:
  • Разработка веб-приложений, устойчивых к SQL-инъекциям
  • Применение специализированных межсетевых экранов для защиты не только баз данных, но и веб-приложений (WAF)
  • Оценка возможности проникновения в систему хранения данных путем моделирования атаки злоумышленника (т.н. «пентест»)
  • Аудит данных и выявление случаев взлома и утечки данных для принятия необходимых мер
  • Чёткое следование рекомендациям разработчиков баз данных и сопутствующего программного обеспечения по обеспечению их защиты и безопасного использования.
Комментарии