• Открыта запись на вторую часть курса по анонимности и безопасности в сети интернет "Paranoid II" от команды codeby. Анонимные роутеры, Подъём, настройка и администрирование Tor-ноды, Работа с железом ПК, Удаление аппаратных закладок, Минимизация рисков, Авторские разработки и многое другое. Подробнее ...

Статья Эксплуатация инъекций в ORM Doctrine (DQL).

r0hack

r0hack

DAG
Gold Team
29.09.2017
481
901
Всем Салам. В ходе пентестов, уже несколько раз сталкивались с ORM-Doctrine и наличием там возможности эксплуатации инъекций, а в сети про DQL инъекции ничего нет. В связи с этим был сделан этот небольшой ресерч.
В дальнейшем будет изучено еще глубже и другие ORM и их диалекты, например, Phalcon (Phql).

В современных веб-приложениях всё реже бывают инъекции, все используют подготовленные запросы и ORM, но мы до сих пор встречаем инъекции при пентестах.

Особый интерес представляют диалекты SQL, встроенные в ORM-библиотеки. Это дополнительная абстракция, которая также подвержена инъекциям, при этом могут возникать уязвимости и при трансляции выражений из диалекта в конкретную реализацию SQL.

Введение

ORM — это библиотека, связывающая объекты и их атрибуты в коде с таблицами и полями в базе данных.

Абстракция ORM позволяет представлять реляционные таблицы БД в виде обычных объектов и обращаться с ними, как с объектами.

Эксплуатация инъекций в ORM Doctrine (DQL).


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

Для чего используют ORM?

Понятно, что отсутствие необходимости вручную писать сотни SQL-запрос упрощает процесс разработки, особенно в крупных проектах.

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

Само по себе использование ORM не является средством защиты от инъекций, но при правильном использовании библиотеки предоставляют средства для параметризованных и подготовленных запросов.

Эксплуатация инъекций в ORM Doctrine (DQL).


Doctrine и DQL

Существует множество ORM-библиотек для различных языков программирования и фреймворков. Остановимся подробнее на проекте Doctrine, написанном на PHP, и эксплуатации инъекций в Doctrine Query Language. Doctrine по умолчанию используется в популярном PHP-фреймворке Symfony.

Пользоваться Doctrine можно как осуществляя действия над объектами в PHP-коде (при помощи QueryBuilder), так и вручную выполняя DQL-запросы. Также возможно выполнение «сырых» запросов напрямую в SQL.

Язык DQL основан на HQL (Hibernate Query Language в Java-библиотеке Hibernate) и является подмножеством SQL, но в нём всё равно довольно много возможностей, которые могут помочь и при эксплуатации инъекций.

DQL поддерживает привычные операторы SELECT, UPDATE, DELETE, однако нет реализации операторов INSERT и UNION, выражения LIMIT (необходимо использование метода setMaxResults). Оператор UNION авторы библиотеки не стали реализовывать ввиду строгой типизации DQL (а UNION подразумевает возможность выборки данных разного типа).

Также в DQL реализована поддержка подзапросов, а также выражений JOIN, WHERE, ORDER BY, LIMIT, HAVING, IN и т.д.

Описание синтаксиса DQL:

Ниже приведён список встроенных функций в DQL, которые можно использовать после выражений SELECT, WHERE и HAVING. Также после выражений SELECT и GROUP BY можно использовать функции AVG, COUNT, MIN, MAX, SUM.

Эксплуатация инъекций в ORM Doctrine (DQL).

Как и во многих СУБД, в Doctrine можно создать собственную реализацию функции (User Defined Function) на PHP и сделать её доступной из DQL.

Инъекции в DQL

Вот как выглядит создание SQL-запроса для выборки данных в Doctrine при работе с объектами в коде:

Эксплуатация инъекций в ORM Doctrine (DQL).


А ниже показана разница между DQL-запросом и SQL-запросом:

PHP:
$dqlQuery = "SELECT p FROM App\Entity\Post p WHERE id = '.$query.' ORDER BY p.publishedAt DESC";
PHP:
$sqlQuery = "SELECT * FROM post WHERE id = '.$query.' ORDER BY publishedAt DESC";
Очевидно, в обоих случаях есть конкатенация некоторой переменной с запросом. Если это пользовательские данные, возможно проведение DQL-инъекции.

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

Посмотрим, что происходит при создании такого запроса (QueryBuilder вызван из метода класса Post):

Эксплуатация инъекций в ORM Doctrine (DQL).


DQL-запрос преобразуется в синтаксическое дерево, после чего генерируется уже SQL-запрос в грамматике подключённой СУБД.

Техники инъекций

В зависимости от используемой СУБД, типа запроса, контекста инъекции и настроек (наличие debug-режима), возможны различные алгоритмы эксплуатации инъекции, такие как Boolean Based и Error Based.

  • Boolean Based
Функция substring и подзапросы дают возможность перебором посимвольно извлекать значения атрибутов моделей:

Эксплуатация инъекций в ORM Doctrine (DQL).


Код:
1 or 1=(select 1 from App\Entity\User a where a.id=1 and substring(a.password,1,1)='$')
Эксплуатация инъекций в ORM Doctrine (DQL).


Из скриншотов видно, что мы получили значение первого символа хеш-суммы пароля («$»). При этом в операторе SELECT мы использовали полное имя модели User. Нет простого способа получить перечень всех моделей.

  • Error Based (SQLite)
При использовании СУБД SQLite есть ещё одна особенность — диалект SQLite достаточно бедный, а DQL обеспечивает одинаковый интерфейс независимо от используемой СУБД. Поэтому, при отсутствии каких-то нативных функций в SQLite, приходится писать их реализацию на PHP.

Это касается функций udfSqrt, udfMod, udfLocate (соответствующие DQL-функции: SQRT, MOD, LOCATE). При передаче некорректных данных в эти функции возникает исключение на уровне PHP, а не на уровне СУБД, поэтому, при отображении ошибок, возможна утечка результата SQL-подзапроса целиком.

Ошибка:

Эксплуатация инъекций в ORM Doctrine (DQL).


Результат SQL-подзапроса с хешем пароля:

Эксплуатация инъекций в ORM Doctrine (DQL).


Понятно, что при отсутствии debug-режима приложение вряд ли отобразит эти данные, но, тем не менее, возможна эксплуатация Error Based инъекции перебором (извлекать бит информации по наличию или отсутствию внутренней ошибки).

  • Инъекции в ORDER BY
Грамматика DQL не предусматривает использование сложных выражений и подзапросов после ORDER BY и GROUP BY, так что эксплуатация инъекции в таком контексте не представляется возможной, парсер пропустит лишь литералы.

  • Инъекция в IN
В качестве аргументов выражения IN можно передать подзапрос, что даёт различные возможности для эксплуатации инъекций, например, при помощи техники Error Based:

PHP:
$dqlQuery = "SELECT p FROM App\Entity\Post p WHERE p.id IN (select sqrt(a.password) from App\Entity\User a where a.id=2)";
  • Инъекция в UPDATE.
Оператор UPDATE позволяет записывать в значение атрибута модели результат выполнения подзапроса, так что можно извлечь данные целиком по стороннему каналу (записав секретные данные в таблицу с публичными данными):

SQL:
UPDATE App\Entity\Post p SET p.title = (SELECT u.password FROM App\Entity\User u WHERE u.id = 2), slug = testslug, summary = testsum, content = testcon WHERE id = 25
Выводы

Использование ORM — не панацея от SQL-инъекций. Необходимо тщательно валидировать и санитизировать передаваемые пользователями данные, использовать подготовленные запросы.

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

 
Мы в соцсетях:  ТелеграмВконтактеДзенФейсбукТвиттерЮтуб