При тестировании нового проекта я наткнулся на что-то похожее на SQL-инъекцию. При входе в веб-приложение отправляет запрос POST с телом JSON:

POST /login HTTP/1.1
Host:<host>
User-Agent: Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Content-Type: application/json
Content-Length: 65
Cookie: JSESSIONID=D6F3D7EAC2FA80E37726928882610255
Connection: close
{"username":"test","password":"test"}

Я немедленно проверил ввод для SQL-инъекции, добавив к имени пользователя дополнительную букву «». Ответ содержит исключение, означающее, что что-то пошло не так. Посмотрев на ответ сервера, можно определить, что «org.hibernate.QueryException» произошло из-за недопустимого запроса:

К сожалению, это означает, что у нас есть не SQL-инъекция, а HQL-инъекция. Hibernate Query Language (HQL) - это язык запросов, похожий на SQL, но работающий с постоянными объектами, а не с таблицами и столбцами. HQL переводится в SQL фреймворком Hibernate.

Честно говоря, это был первый раз, когда я наткнулся на такую ​​инъекцию, поэтому я начал проводить более общее тестирование SQL-инъекции. Из приведенного выше исключения я знал, что запрос выглядит следующим образом («тест» - это точка внедрения):

SELECT u FROM Users u WHERE u.active = 1 AND login = 'test'

Это типичный запрос входа в систему, который ищет действительную сущность пользователя для предоставленного имени пользователя. На следующем шаге я отправил «test» или «1» = ’1» и получил еще одно исключение:

Новое исключение - это «javax.persistance.NonUniqueResultException». Это означает, что мы получили более одного ожидаемого результата. После дальнейшего тестирования я заметил, что сервер отвечает ошибкой HTTP 422, когда в базе данных нет действительного пользователя (говоря на HQL: «u.active = 1 AND login = 'user'» оценивается как false для всех пользовательских сущностей) .

Хорошо, пойдем дальше и прочитаем некоторые данные. Моя первая попытка заключалась в том, чтобы перечислить всех доступных пользователей. Проблема в том, что HQL не поддерживает все функции SQL (например, оператор UNION, а также метаинформация отсутствуют). Информации об инъекциях HQL не так много. Я добавил к запросу что-то вроде «test’ OR substring (login, 1,1) = ’a’ »и получил исключение« NonUniqueResultException ». Отлично. К сожалению, мне не удалось извлечь более двух символов.

В конце концов я обнаружил, что единственный способ различать запросы - это «NonUniqueResultException», но после более чем двух символов есть только один результат, следовательно, «NonUniqueResultException». Поэтому мне нужно было найти способ вызвать исключение NonUniqueResultException. Поработав, я пришел к следующему запросу, который соответствует моим требованиям:

SELECT u FROM Users u WHERE u.active = 1 AND login = 'test' OR (select count(login) from Users u where login LIKE 'a%')>=1 AND '1'='1'

Введенный подзапрос подсчитывает все имена пользователей, которые начинаются (в данном случае) с «a». Запрос предназначен для оценки истинности, когда у нас есть хотя бы один действительный пользователь. Я быстро протестировал это с помощью Burp Suite:

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

После того, как я нашел успешный способ эксфильтрации данных с использованием подхода, основанного на ошибках, пришло время его автоматизировать. Для этого я написал небольшой скрипт на Python:

Благодаря этому я смог перечислить всех доступных пользователей, включая их пароли. Ага :)

Печально то, что я не мог читать произвольные данные, потому что в HQL отсутствуют все удобные функции SQL, такие как метаданные о доступных таблицах и столбцах. Это связано с ограничением HQL сущностями с отображением объектов. Я пробовал несколько методов, предложенных http://blog.h3xstream.com/2014/02/hql-for-pentesters.html, но ни один из них не работал в моем случае.